xref: /titanic_52/usr/src/uts/common/os/modsysfile.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/inttypes.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/disp.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/sysconf.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/hwconf.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/kobj_lex.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/callb.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/dacf.h>
55*7c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate struct hwc_class *hcl_head;	/* head of list of classes */
58*7c478bd9Sstevel@tonic-gate static kmutex_t hcl_lock;	/* for accessing list of classes */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #define	DAFILE		"/etc/driver_aliases"
61*7c478bd9Sstevel@tonic-gate #define	CLASSFILE	"/etc/driver_classes"
62*7c478bd9Sstevel@tonic-gate #define	DACFFILE	"/etc/dacf.conf"
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate static char class_file[] = CLASSFILE;
65*7c478bd9Sstevel@tonic-gate static char dafile[] = DAFILE;
66*7c478bd9Sstevel@tonic-gate static char dacffile[] = DACFFILE;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate char *systemfile = "etc/system";	/* name of ascii system file */
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate static struct sysparam *sysparam_hd;	/* head of parameters list */
71*7c478bd9Sstevel@tonic-gate static struct sysparam *sysparam_tl;	/* tail of parameters list */
72*7c478bd9Sstevel@tonic-gate static vmem_t *mod_sysfile_arena;	/* parser memory */
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate char obp_bootpath[BO_MAXOBJNAME];	/* bootpath from obp */
75*7c478bd9Sstevel@tonic-gate char svm_bootpath[BO_MAXOBJNAME];	/* bootpath redirected via rootdev */
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate #if defined(_PSM_MODULES)
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate struct psm_mach {
80*7c478bd9Sstevel@tonic-gate 	struct psm_mach *m_next;
81*7c478bd9Sstevel@tonic-gate 	char		*m_machname;
82*7c478bd9Sstevel@tonic-gate };
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate static struct psm_mach *pmach_head;	/* head of list of classes */
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #define	MACHFILE	"/etc/mach"
87*7c478bd9Sstevel@tonic-gate static char mach_file[] = MACHFILE;
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate #endif	/* _PSM_MODULES */
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #if defined(_RTC_CONFIG)
92*7c478bd9Sstevel@tonic-gate static char rtc_config_file[] = "/etc/rtc_config";
93*7c478bd9Sstevel@tonic-gate #endif
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate static void sys_set_var(int, struct sysparam *, void *);
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate static void setparams(void);
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * driver.conf parse thread control structure
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate struct hwc_parse_mt {
103*7c478bd9Sstevel@tonic-gate 	ksema_t		sema;
104*7c478bd9Sstevel@tonic-gate 	char		*name;		/* name of .conf files */
105*7c478bd9Sstevel@tonic-gate 	struct par_list	**pl;		/* parsed parent list */
106*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	**props;	/* parsed properties */
107*7c478bd9Sstevel@tonic-gate 	int		rv;		/* return value */
108*7c478bd9Sstevel@tonic-gate };
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate static int hwc_parse_now(char *, struct par_list **, ddi_prop_t **);
111*7c478bd9Sstevel@tonic-gate static void hwc_parse_thread(struct hwc_parse_mt *);
112*7c478bd9Sstevel@tonic-gate static struct hwc_parse_mt *hwc_parse_mtalloc(char *, struct par_list **,
113*7c478bd9Sstevel@tonic-gate 	ddi_prop_t **);
114*7c478bd9Sstevel@tonic-gate static void hwc_parse_mtfree(struct hwc_parse_mt *);
115*7c478bd9Sstevel@tonic-gate static void add_spec(struct hwc_spec *, struct par_list **);
116*7c478bd9Sstevel@tonic-gate static void add_props(struct hwc_spec *, ddi_prop_t **);
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate static void check_system_file(void);
119*7c478bd9Sstevel@tonic-gate static int sysparam_compare_entry(struct sysparam *, struct sysparam *);
120*7c478bd9Sstevel@tonic-gate static char *sysparam_type_to_str(int);
121*7c478bd9Sstevel@tonic-gate static void sysparam_count_entry(struct sysparam *, int *, u_longlong_t *);
122*7c478bd9Sstevel@tonic-gate static void sysparam_print_warning(struct sysparam *, u_longlong_t);
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
125*7c478bd9Sstevel@tonic-gate static int parse_debug_on = 0;
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate /*VARARGS1*/
128*7c478bd9Sstevel@tonic-gate static void
129*7c478bd9Sstevel@tonic-gate parse_debug(struct _buf *file, char *fmt, ...)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	va_list adx;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	if (parse_debug_on) {
134*7c478bd9Sstevel@tonic-gate 		va_start(adx, fmt);
135*7c478bd9Sstevel@tonic-gate 		vprintf(fmt, adx);
136*7c478bd9Sstevel@tonic-gate 		if (file)
137*7c478bd9Sstevel@tonic-gate 			printf(" on line %d of %s\n", kobj_linenum(file),
138*7c478bd9Sstevel@tonic-gate 				kobj_filename(file));
139*7c478bd9Sstevel@tonic-gate 		va_end(adx);
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate }
142*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate #define	FE_BUFLEN 256
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/
147*7c478bd9Sstevel@tonic-gate void
148*7c478bd9Sstevel@tonic-gate kobj_file_err(int type,  struct _buf *file, char *fmt, ...)
149*7c478bd9Sstevel@tonic-gate {
150*7c478bd9Sstevel@tonic-gate 	va_list ap;
151*7c478bd9Sstevel@tonic-gate 	/*
152*7c478bd9Sstevel@tonic-gate 	 * If we're in trouble, we might be short on stack... be paranoid
153*7c478bd9Sstevel@tonic-gate 	 */
154*7c478bd9Sstevel@tonic-gate 	char *buf = kmem_alloc(FE_BUFLEN, KM_SLEEP);
155*7c478bd9Sstevel@tonic-gate 	char *trailer = kmem_alloc(FE_BUFLEN, KM_SLEEP);
156*7c478bd9Sstevel@tonic-gate 	char *fmt_str = kmem_alloc(FE_BUFLEN, KM_SLEEP);
157*7c478bd9Sstevel@tonic-gate 	char prefix = '\0';
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
160*7c478bd9Sstevel@tonic-gate 	if (strchr("^!?", fmt[0]) != NULL) {
161*7c478bd9Sstevel@tonic-gate 		prefix = fmt[0];
162*7c478bd9Sstevel@tonic-gate 		fmt++;
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 	(void) vsnprintf(buf, FE_BUFLEN, fmt, ap);
165*7c478bd9Sstevel@tonic-gate 	va_end(ap);
166*7c478bd9Sstevel@tonic-gate 	(void) snprintf(trailer, FE_BUFLEN, " on line %d of %s",
167*7c478bd9Sstevel@tonic-gate 	    kobj_linenum(file), kobj_filename(file));
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	/*
170*7c478bd9Sstevel@tonic-gate 	 * If prefixed with !^?, prepend that character
171*7c478bd9Sstevel@tonic-gate 	 */
172*7c478bd9Sstevel@tonic-gate 	if (prefix != '\0') {
173*7c478bd9Sstevel@tonic-gate 		(void) snprintf(fmt_str, FE_BUFLEN, "%c%%s%%s", prefix);
174*7c478bd9Sstevel@tonic-gate 	} else {
175*7c478bd9Sstevel@tonic-gate 		(void) strncpy(fmt_str, "%s%s", FE_BUFLEN);
176*7c478bd9Sstevel@tonic-gate 	}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	cmn_err(type, fmt_str, buf, trailer);
179*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, FE_BUFLEN);
180*7c478bd9Sstevel@tonic-gate 	kmem_free(trailer, FE_BUFLEN);
181*7c478bd9Sstevel@tonic-gate 	kmem_free(fmt_str, FE_BUFLEN);
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
185*7c478bd9Sstevel@tonic-gate char *tokennames[] = {
186*7c478bd9Sstevel@tonic-gate 	"EQUALS",
187*7c478bd9Sstevel@tonic-gate 	"AMPERSAND",
188*7c478bd9Sstevel@tonic-gate 	"BIT_OR",
189*7c478bd9Sstevel@tonic-gate 	"STAR",
190*7c478bd9Sstevel@tonic-gate 	"POUND",
191*7c478bd9Sstevel@tonic-gate 	"COLON",
192*7c478bd9Sstevel@tonic-gate 	"SEMICOLON",
193*7c478bd9Sstevel@tonic-gate 	"COMMA",
194*7c478bd9Sstevel@tonic-gate 	"SLASH",
195*7c478bd9Sstevel@tonic-gate 	"WHITE_SPACE",
196*7c478bd9Sstevel@tonic-gate 	"NEWLINE",
197*7c478bd9Sstevel@tonic-gate 	"EOF",
198*7c478bd9Sstevel@tonic-gate 	"STRING",
199*7c478bd9Sstevel@tonic-gate 	"HEXVAL",
200*7c478bd9Sstevel@tonic-gate 	"DECVAL",
201*7c478bd9Sstevel@tonic-gate 	"NAME"
202*7c478bd9Sstevel@tonic-gate };
203*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate token_t
206*7c478bd9Sstevel@tonic-gate kobj_lex(struct _buf *file, char *val, size_t size)
207*7c478bd9Sstevel@tonic-gate {
208*7c478bd9Sstevel@tonic-gate 	char	*cp;
209*7c478bd9Sstevel@tonic-gate 	int	ch, oval, badquote;
210*7c478bd9Sstevel@tonic-gate 	size_t	remain;
211*7c478bd9Sstevel@tonic-gate 	token_t token;
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	if (size < 2)
214*7c478bd9Sstevel@tonic-gate 		return (-1);
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	cp = val;
217*7c478bd9Sstevel@tonic-gate 	while ((ch = kobj_getc(file)) == ' ' || ch == '\t')
218*7c478bd9Sstevel@tonic-gate 		;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	remain = size - 1;
221*7c478bd9Sstevel@tonic-gate 	*cp++ = (char)ch;
222*7c478bd9Sstevel@tonic-gate 	switch (ch) {
223*7c478bd9Sstevel@tonic-gate 	case '=':
224*7c478bd9Sstevel@tonic-gate 		token = EQUALS;
225*7c478bd9Sstevel@tonic-gate 		break;
226*7c478bd9Sstevel@tonic-gate 	case '&':
227*7c478bd9Sstevel@tonic-gate 		token = AMPERSAND;
228*7c478bd9Sstevel@tonic-gate 		break;
229*7c478bd9Sstevel@tonic-gate 	case '|':
230*7c478bd9Sstevel@tonic-gate 		token = BIT_OR;
231*7c478bd9Sstevel@tonic-gate 		break;
232*7c478bd9Sstevel@tonic-gate 	case '*':
233*7c478bd9Sstevel@tonic-gate 		token = STAR;
234*7c478bd9Sstevel@tonic-gate 		break;
235*7c478bd9Sstevel@tonic-gate 	case '#':
236*7c478bd9Sstevel@tonic-gate 		token = POUND;
237*7c478bd9Sstevel@tonic-gate 		break;
238*7c478bd9Sstevel@tonic-gate 	case ':':
239*7c478bd9Sstevel@tonic-gate 		token = COLON;
240*7c478bd9Sstevel@tonic-gate 		break;
241*7c478bd9Sstevel@tonic-gate 	case ';':
242*7c478bd9Sstevel@tonic-gate 		token = SEMICOLON;
243*7c478bd9Sstevel@tonic-gate 		break;
244*7c478bd9Sstevel@tonic-gate 	case ',':
245*7c478bd9Sstevel@tonic-gate 		token = COMMA;
246*7c478bd9Sstevel@tonic-gate 		break;
247*7c478bd9Sstevel@tonic-gate 	case '/':
248*7c478bd9Sstevel@tonic-gate 		token = SLASH;
249*7c478bd9Sstevel@tonic-gate 		break;
250*7c478bd9Sstevel@tonic-gate 	case ' ':
251*7c478bd9Sstevel@tonic-gate 	case '\t':
252*7c478bd9Sstevel@tonic-gate 	case '\f':
253*7c478bd9Sstevel@tonic-gate 		while ((ch = kobj_getc(file)) == ' ' ||
254*7c478bd9Sstevel@tonic-gate 		    ch == '\t' || ch == '\f') {
255*7c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
256*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
257*7c478bd9Sstevel@tonic-gate 				return (-1);
258*7c478bd9Sstevel@tonic-gate 			}
259*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)ch;
260*7c478bd9Sstevel@tonic-gate 		}
261*7c478bd9Sstevel@tonic-gate 		(void) kobj_ungetc(file);
262*7c478bd9Sstevel@tonic-gate 		token = WHITE_SPACE;
263*7c478bd9Sstevel@tonic-gate 		break;
264*7c478bd9Sstevel@tonic-gate 	case '\n':
265*7c478bd9Sstevel@tonic-gate 	case '\r':
266*7c478bd9Sstevel@tonic-gate 		token = NEWLINE;
267*7c478bd9Sstevel@tonic-gate 		break;
268*7c478bd9Sstevel@tonic-gate 	case '"':
269*7c478bd9Sstevel@tonic-gate 		remain++;
270*7c478bd9Sstevel@tonic-gate 		cp--;
271*7c478bd9Sstevel@tonic-gate 		badquote = 0;
272*7c478bd9Sstevel@tonic-gate 		while (!badquote && (ch  = kobj_getc(file)) != '"') {
273*7c478bd9Sstevel@tonic-gate 			switch (ch) {
274*7c478bd9Sstevel@tonic-gate 			case '\n':
275*7c478bd9Sstevel@tonic-gate 			case -1:
276*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, "Missing \"");
277*7c478bd9Sstevel@tonic-gate 				remain = size - 1;
278*7c478bd9Sstevel@tonic-gate 				cp = val;
279*7c478bd9Sstevel@tonic-gate 				*cp++ = '\n';
280*7c478bd9Sstevel@tonic-gate 				badquote = 1;
281*7c478bd9Sstevel@tonic-gate 				/* since we consumed the newline/EOF */
282*7c478bd9Sstevel@tonic-gate 				(void) kobj_ungetc(file);
283*7c478bd9Sstevel@tonic-gate 				break;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 			case '\\':
286*7c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
287*7c478bd9Sstevel@tonic-gate 					*cp = '\0';
288*7c478bd9Sstevel@tonic-gate 					return (-1);
289*7c478bd9Sstevel@tonic-gate 				}
290*7c478bd9Sstevel@tonic-gate 				ch = (char)kobj_getc(file);
291*7c478bd9Sstevel@tonic-gate 				if (!isdigit(ch)) {
292*7c478bd9Sstevel@tonic-gate 					/* escape the character */
293*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
294*7c478bd9Sstevel@tonic-gate 					break;
295*7c478bd9Sstevel@tonic-gate 				}
296*7c478bd9Sstevel@tonic-gate 				oval = 0;
297*7c478bd9Sstevel@tonic-gate 				while (ch >= '0' && ch <= '7') {
298*7c478bd9Sstevel@tonic-gate 					ch -= '0';
299*7c478bd9Sstevel@tonic-gate 					oval = (oval << 3) + ch;
300*7c478bd9Sstevel@tonic-gate 					ch = (char)kobj_getc(file);
301*7c478bd9Sstevel@tonic-gate 				}
302*7c478bd9Sstevel@tonic-gate 				(void) kobj_ungetc(file);
303*7c478bd9Sstevel@tonic-gate 				/* check for character overflow? */
304*7c478bd9Sstevel@tonic-gate 				if (oval > 127) {
305*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
306*7c478bd9Sstevel@tonic-gate 					    "Character "
307*7c478bd9Sstevel@tonic-gate 					    "overflow detected.");
308*7c478bd9Sstevel@tonic-gate 				}
309*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)oval;
310*7c478bd9Sstevel@tonic-gate 				break;
311*7c478bd9Sstevel@tonic-gate 			default:
312*7c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
313*7c478bd9Sstevel@tonic-gate 					*cp = '\0';
314*7c478bd9Sstevel@tonic-gate 					return (-1);
315*7c478bd9Sstevel@tonic-gate 				}
316*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
317*7c478bd9Sstevel@tonic-gate 				break;
318*7c478bd9Sstevel@tonic-gate 			}
319*7c478bd9Sstevel@tonic-gate 		}
320*7c478bd9Sstevel@tonic-gate 		token = STRING;
321*7c478bd9Sstevel@tonic-gate 		break;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	case -1:
324*7c478bd9Sstevel@tonic-gate 		token = EOF;
325*7c478bd9Sstevel@tonic-gate 		break;
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	default:
328*7c478bd9Sstevel@tonic-gate 		/*
329*7c478bd9Sstevel@tonic-gate 		 * detect a lone '-' (including at the end of a line), and
330*7c478bd9Sstevel@tonic-gate 		 * identify it as a 'name'
331*7c478bd9Sstevel@tonic-gate 		 */
332*7c478bd9Sstevel@tonic-gate 		if (ch == '-') {
333*7c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
334*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
335*7c478bd9Sstevel@tonic-gate 				return (-1);
336*7c478bd9Sstevel@tonic-gate 			}
337*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = kobj_getc(file));
338*7c478bd9Sstevel@tonic-gate 			if (iswhite(ch) || (ch == '\n')) {
339*7c478bd9Sstevel@tonic-gate 				(void) kobj_ungetc(file);
340*7c478bd9Sstevel@tonic-gate 				remain++;
341*7c478bd9Sstevel@tonic-gate 				cp--;
342*7c478bd9Sstevel@tonic-gate 				token = NAME;
343*7c478bd9Sstevel@tonic-gate 				break;
344*7c478bd9Sstevel@tonic-gate 			}
345*7c478bd9Sstevel@tonic-gate 		} else if (isunary(ch)) {
346*7c478bd9Sstevel@tonic-gate 			if (--remain == 0) {
347*7c478bd9Sstevel@tonic-gate 				*cp = '\0';
348*7c478bd9Sstevel@tonic-gate 				return (-1);
349*7c478bd9Sstevel@tonic-gate 			}
350*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)(ch = kobj_getc(file));
351*7c478bd9Sstevel@tonic-gate 		}
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 		if (isdigit(ch)) {
355*7c478bd9Sstevel@tonic-gate 			if (ch == '0') {
356*7c478bd9Sstevel@tonic-gate 				if ((ch = kobj_getc(file)) == 'x') {
357*7c478bd9Sstevel@tonic-gate 					if (--remain == 0) {
358*7c478bd9Sstevel@tonic-gate 						*cp = '\0';
359*7c478bd9Sstevel@tonic-gate 						return (-1);
360*7c478bd9Sstevel@tonic-gate 					}
361*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
362*7c478bd9Sstevel@tonic-gate 					ch = kobj_getc(file);
363*7c478bd9Sstevel@tonic-gate 					while (isxdigit(ch)) {
364*7c478bd9Sstevel@tonic-gate 						if (--remain == 0) {
365*7c478bd9Sstevel@tonic-gate 							*cp = '\0';
366*7c478bd9Sstevel@tonic-gate 							return (-1);
367*7c478bd9Sstevel@tonic-gate 						}
368*7c478bd9Sstevel@tonic-gate 						*cp++ = (char)ch;
369*7c478bd9Sstevel@tonic-gate 						ch = kobj_getc(file);
370*7c478bd9Sstevel@tonic-gate 					}
371*7c478bd9Sstevel@tonic-gate 					(void) kobj_ungetc(file);
372*7c478bd9Sstevel@tonic-gate 					token = HEXVAL;
373*7c478bd9Sstevel@tonic-gate 				} else {
374*7c478bd9Sstevel@tonic-gate 					goto digit;
375*7c478bd9Sstevel@tonic-gate 				}
376*7c478bd9Sstevel@tonic-gate 			} else {
377*7c478bd9Sstevel@tonic-gate 				ch = kobj_getc(file);
378*7c478bd9Sstevel@tonic-gate digit:
379*7c478bd9Sstevel@tonic-gate 				while (isdigit(ch)) {
380*7c478bd9Sstevel@tonic-gate 					if (--remain == 0) {
381*7c478bd9Sstevel@tonic-gate 						*cp = '\0';
382*7c478bd9Sstevel@tonic-gate 						return (-1);
383*7c478bd9Sstevel@tonic-gate 					}
384*7c478bd9Sstevel@tonic-gate 					*cp++ = (char)ch;
385*7c478bd9Sstevel@tonic-gate 					ch = kobj_getc(file);
386*7c478bd9Sstevel@tonic-gate 				}
387*7c478bd9Sstevel@tonic-gate 				(void) kobj_ungetc(file);
388*7c478bd9Sstevel@tonic-gate 				token = DECVAL;
389*7c478bd9Sstevel@tonic-gate 			}
390*7c478bd9Sstevel@tonic-gate 		} else if (isalpha(ch) || ch == '\\' || ch == '_') {
391*7c478bd9Sstevel@tonic-gate 			if (ch != '\\') {
392*7c478bd9Sstevel@tonic-gate 				ch = kobj_getc(file);
393*7c478bd9Sstevel@tonic-gate 			} else {
394*7c478bd9Sstevel@tonic-gate 				/*
395*7c478bd9Sstevel@tonic-gate 				 * if the character was a backslash,
396*7c478bd9Sstevel@tonic-gate 				 * back up so we can overwrite it with
397*7c478bd9Sstevel@tonic-gate 				 * the next (i.e. escaped) character.
398*7c478bd9Sstevel@tonic-gate 				 */
399*7c478bd9Sstevel@tonic-gate 				remain++;
400*7c478bd9Sstevel@tonic-gate 				cp--;
401*7c478bd9Sstevel@tonic-gate 			}
402*7c478bd9Sstevel@tonic-gate 			while (isnamechar(ch) || ch == '\\') {
403*7c478bd9Sstevel@tonic-gate 				if (ch == '\\')
404*7c478bd9Sstevel@tonic-gate 					ch = kobj_getc(file);
405*7c478bd9Sstevel@tonic-gate 				if (--remain == 0) {
406*7c478bd9Sstevel@tonic-gate 					*cp = '\0';
407*7c478bd9Sstevel@tonic-gate 					return (-1);
408*7c478bd9Sstevel@tonic-gate 				}
409*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
410*7c478bd9Sstevel@tonic-gate 				ch = kobj_getc(file);
411*7c478bd9Sstevel@tonic-gate 			}
412*7c478bd9Sstevel@tonic-gate 			(void) kobj_ungetc(file);
413*7c478bd9Sstevel@tonic-gate 			token = NAME;
414*7c478bd9Sstevel@tonic-gate 		} else {
415*7c478bd9Sstevel@tonic-gate 			return (-1);
416*7c478bd9Sstevel@tonic-gate 		}
417*7c478bd9Sstevel@tonic-gate 		break;
418*7c478bd9Sstevel@tonic-gate 	}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
423*7c478bd9Sstevel@tonic-gate 	parse_debug(NULL, "kobj_lex: token %s value '%s'\n", tokennames[token],
424*7c478bd9Sstevel@tonic-gate 	    val);
425*7c478bd9Sstevel@tonic-gate #endif
426*7c478bd9Sstevel@tonic-gate 	return (token);
427*7c478bd9Sstevel@tonic-gate }
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate /*
430*7c478bd9Sstevel@tonic-gate  * Leave NEWLINE as the next character.
431*7c478bd9Sstevel@tonic-gate  */
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate void
434*7c478bd9Sstevel@tonic-gate kobj_find_eol(struct _buf *file)
435*7c478bd9Sstevel@tonic-gate {
436*7c478bd9Sstevel@tonic-gate 	int ch;
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	while ((ch = kobj_getc(file)) != -1) {
439*7c478bd9Sstevel@tonic-gate 		if (isnewline(ch)) {
440*7c478bd9Sstevel@tonic-gate 			(void) kobj_ungetc(file);
441*7c478bd9Sstevel@tonic-gate 			break;
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 	}
444*7c478bd9Sstevel@tonic-gate }
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate /*
447*7c478bd9Sstevel@tonic-gate  * The ascii system file is read and processed.
448*7c478bd9Sstevel@tonic-gate  *
449*7c478bd9Sstevel@tonic-gate  * The syntax of commands is as follows:
450*7c478bd9Sstevel@tonic-gate  *
451*7c478bd9Sstevel@tonic-gate  * '*' in column 1 is a comment line.
452*7c478bd9Sstevel@tonic-gate  * <command> : <value>
453*7c478bd9Sstevel@tonic-gate  *
454*7c478bd9Sstevel@tonic-gate  * command is EXCLUDE, INCLUDE, FORCELOAD, ROOTDEV, ROOTFS,
455*7c478bd9Sstevel@tonic-gate  *	SWAPDEV, SWAPFS, MODDIR, SET
456*7c478bd9Sstevel@tonic-gate  *
457*7c478bd9Sstevel@tonic-gate  * value is an ascii string meaningful for the command.
458*7c478bd9Sstevel@tonic-gate  */
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate /*
461*7c478bd9Sstevel@tonic-gate  * Table of commands
462*7c478bd9Sstevel@tonic-gate  */
463*7c478bd9Sstevel@tonic-gate static struct modcmd modcmd[] = {
464*7c478bd9Sstevel@tonic-gate 	{ "EXCLUDE",	MOD_EXCLUDE	},
465*7c478bd9Sstevel@tonic-gate 	{ "exclude",	MOD_EXCLUDE	},
466*7c478bd9Sstevel@tonic-gate 	{ "INCLUDE",	MOD_INCLUDE	},
467*7c478bd9Sstevel@tonic-gate 	{ "include",	MOD_INCLUDE	},
468*7c478bd9Sstevel@tonic-gate 	{ "FORCELOAD",	MOD_FORCELOAD	},
469*7c478bd9Sstevel@tonic-gate 	{ "forceload",	MOD_FORCELOAD	},
470*7c478bd9Sstevel@tonic-gate 	{ "ROOTDEV",	MOD_ROOTDEV	},
471*7c478bd9Sstevel@tonic-gate 	{ "rootdev",	MOD_ROOTDEV	},
472*7c478bd9Sstevel@tonic-gate 	{ "ROOTFS",	MOD_ROOTFS	},
473*7c478bd9Sstevel@tonic-gate 	{ "rootfs",	MOD_ROOTFS	},
474*7c478bd9Sstevel@tonic-gate 	{ "SWAPDEV",	MOD_SWAPDEV	},
475*7c478bd9Sstevel@tonic-gate 	{ "swapdev",	MOD_SWAPDEV	},
476*7c478bd9Sstevel@tonic-gate 	{ "SWAPFS",	MOD_SWAPFS	},
477*7c478bd9Sstevel@tonic-gate 	{ "swapfs",	MOD_SWAPFS	},
478*7c478bd9Sstevel@tonic-gate 	{ "MODDIR",	MOD_MODDIR	},
479*7c478bd9Sstevel@tonic-gate 	{ "moddir",	MOD_MODDIR	},
480*7c478bd9Sstevel@tonic-gate 	{ "SET",	MOD_SET		},
481*7c478bd9Sstevel@tonic-gate 	{ "set",	MOD_SET		},
482*7c478bd9Sstevel@tonic-gate 	{ "SET32",	MOD_SET32	},
483*7c478bd9Sstevel@tonic-gate 	{ "set32",	MOD_SET32	},
484*7c478bd9Sstevel@tonic-gate 	{ "SET64",	MOD_SET64	},
485*7c478bd9Sstevel@tonic-gate 	{ "set64",	MOD_SET64	},
486*7c478bd9Sstevel@tonic-gate 	{ NULL,		MOD_UNKNOWN	}
487*7c478bd9Sstevel@tonic-gate };
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate static char bad_op[] = "illegal operator '%s' used on a string";
491*7c478bd9Sstevel@tonic-gate static char colon_err[] = "A colon (:) must follow the '%s' command";
492*7c478bd9Sstevel@tonic-gate static char tok_err[] = "Unexpected token '%s'";
493*7c478bd9Sstevel@tonic-gate static char extra_err[] = "extraneous input ignored starting at '%s'";
494*7c478bd9Sstevel@tonic-gate static char oversize_err[] = "value too long";
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate static struct sysparam *
497*7c478bd9Sstevel@tonic-gate do_sysfile_cmd(struct _buf *file, const char *cmd)
498*7c478bd9Sstevel@tonic-gate {
499*7c478bd9Sstevel@tonic-gate 	struct sysparam *sysp;
500*7c478bd9Sstevel@tonic-gate 	struct modcmd *mcp;
501*7c478bd9Sstevel@tonic-gate 	token_t token, op;
502*7c478bd9Sstevel@tonic-gate 	char *cp;
503*7c478bd9Sstevel@tonic-gate 	int ch;
504*7c478bd9Sstevel@tonic-gate 	char tok1[MOD_MAXPATH + 1]; /* used to read the path set by 'moddir' */
505*7c478bd9Sstevel@tonic-gate 	char tok2[64];
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	for (mcp = modcmd; mcp->mc_cmdname != NULL; mcp++) {
508*7c478bd9Sstevel@tonic-gate 		if (strcmp(mcp->mc_cmdname, cmd) == 0)
509*7c478bd9Sstevel@tonic-gate 			break;
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 	sysp = vmem_alloc(mod_sysfile_arena, sizeof (struct sysparam),
512*7c478bd9Sstevel@tonic-gate 	    VM_SLEEP);
513*7c478bd9Sstevel@tonic-gate 	bzero(sysp, sizeof (struct sysparam));
514*7c478bd9Sstevel@tonic-gate 	sysp->sys_op = SETOP_NONE; /* set op to noop initially */
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	switch (sysp->sys_type = mcp->mc_type) {
517*7c478bd9Sstevel@tonic-gate 	case MOD_INCLUDE:
518*7c478bd9Sstevel@tonic-gate 	case MOD_EXCLUDE:
519*7c478bd9Sstevel@tonic-gate 	case MOD_FORCELOAD:
520*7c478bd9Sstevel@tonic-gate 		/*
521*7c478bd9Sstevel@tonic-gate 		 * Are followed by colon.
522*7c478bd9Sstevel@tonic-gate 		 */
523*7c478bd9Sstevel@tonic-gate 	case MOD_ROOTFS:
524*7c478bd9Sstevel@tonic-gate 	case MOD_SWAPFS:
525*7c478bd9Sstevel@tonic-gate 		if ((token = kobj_lex(file, tok1, sizeof (tok1))) == COLON) {
526*7c478bd9Sstevel@tonic-gate 			token = kobj_lex(file, tok1, sizeof (tok1));
527*7c478bd9Sstevel@tonic-gate 		} else {
528*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, colon_err, cmd);
529*7c478bd9Sstevel@tonic-gate 		}
530*7c478bd9Sstevel@tonic-gate 		if (token != NAME) {
531*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, "value expected");
532*7c478bd9Sstevel@tonic-gate 			goto bad;
533*7c478bd9Sstevel@tonic-gate 		}
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 		cp = tok1 + strlen(tok1);
536*7c478bd9Sstevel@tonic-gate 		while ((ch = kobj_getc(file)) != -1 && !iswhite(ch) &&
537*7c478bd9Sstevel@tonic-gate 		    !isnewline(ch)) {
538*7c478bd9Sstevel@tonic-gate 			if (cp - tok1 >= sizeof (tok1) - 1) {
539*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, oversize_err);
540*7c478bd9Sstevel@tonic-gate 				goto bad;
541*7c478bd9Sstevel@tonic-gate 			}
542*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)ch;
543*7c478bd9Sstevel@tonic-gate 		}
544*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		if (ch != -1)
547*7c478bd9Sstevel@tonic-gate 			(void) kobj_ungetc(file);
548*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_type == MOD_INCLUDE)
549*7c478bd9Sstevel@tonic-gate 			return (NULL);
550*7c478bd9Sstevel@tonic-gate 		sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(tok1) + 1,
551*7c478bd9Sstevel@tonic-gate 		    VM_SLEEP);
552*7c478bd9Sstevel@tonic-gate 		(void) strcpy(sysp->sys_ptr, tok1);
553*7c478bd9Sstevel@tonic-gate 		break;
554*7c478bd9Sstevel@tonic-gate 	case MOD_SET:
555*7c478bd9Sstevel@tonic-gate 	case MOD_SET64:
556*7c478bd9Sstevel@tonic-gate 	case MOD_SET32:
557*7c478bd9Sstevel@tonic-gate 	{
558*7c478bd9Sstevel@tonic-gate 		char *var;
559*7c478bd9Sstevel@tonic-gate 		token_t tok3;
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 		if (kobj_lex(file, tok1, sizeof (tok1)) != NAME) {
562*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, "value expected");
563*7c478bd9Sstevel@tonic-gate 			goto bad;
564*7c478bd9Sstevel@tonic-gate 		}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		/*
567*7c478bd9Sstevel@tonic-gate 		 * If the next token is a colon (:),
568*7c478bd9Sstevel@tonic-gate 		 * we have the <modname>:<variable> construct.
569*7c478bd9Sstevel@tonic-gate 		 */
570*7c478bd9Sstevel@tonic-gate 		if ((token = kobj_lex(file, tok2, sizeof (tok2))) == COLON) {
571*7c478bd9Sstevel@tonic-gate 			if ((token = kobj_lex(file, tok2,
572*7c478bd9Sstevel@tonic-gate 			    sizeof (tok2))) == NAME) {
573*7c478bd9Sstevel@tonic-gate 				var = tok2;
574*7c478bd9Sstevel@tonic-gate 				/*
575*7c478bd9Sstevel@tonic-gate 				 * Save the module name.
576*7c478bd9Sstevel@tonic-gate 				 */
577*7c478bd9Sstevel@tonic-gate 				sysp->sys_modnam = vmem_alloc(mod_sysfile_arena,
578*7c478bd9Sstevel@tonic-gate 				    strlen(tok1) + 1, VM_SLEEP);
579*7c478bd9Sstevel@tonic-gate 				(void) strcpy(sysp->sys_modnam, tok1);
580*7c478bd9Sstevel@tonic-gate 				op = kobj_lex(file, tok1, sizeof (tok1));
581*7c478bd9Sstevel@tonic-gate 			} else {
582*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, "value expected");
583*7c478bd9Sstevel@tonic-gate 				goto bad;
584*7c478bd9Sstevel@tonic-gate 			}
585*7c478bd9Sstevel@tonic-gate 		} else {
586*7c478bd9Sstevel@tonic-gate 			/* otherwise, it was the op */
587*7c478bd9Sstevel@tonic-gate 			var = tok1;
588*7c478bd9Sstevel@tonic-gate 			op = token;
589*7c478bd9Sstevel@tonic-gate 		}
590*7c478bd9Sstevel@tonic-gate 		/*
591*7c478bd9Sstevel@tonic-gate 		 * kernel param - place variable name in sys_ptr.
592*7c478bd9Sstevel@tonic-gate 		 */
593*7c478bd9Sstevel@tonic-gate 		sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(var) + 1,
594*7c478bd9Sstevel@tonic-gate 		    VM_SLEEP);
595*7c478bd9Sstevel@tonic-gate 		(void) strcpy(sysp->sys_ptr, var);
596*7c478bd9Sstevel@tonic-gate 		/* set operation */
597*7c478bd9Sstevel@tonic-gate 		switch (op) {
598*7c478bd9Sstevel@tonic-gate 		case EQUALS:
599*7c478bd9Sstevel@tonic-gate 			/* simple assignment */
600*7c478bd9Sstevel@tonic-gate 			sysp->sys_op = SETOP_ASSIGN;
601*7c478bd9Sstevel@tonic-gate 			break;
602*7c478bd9Sstevel@tonic-gate 		case AMPERSAND:
603*7c478bd9Sstevel@tonic-gate 			/* bitwise AND */
604*7c478bd9Sstevel@tonic-gate 			sysp->sys_op = SETOP_AND;
605*7c478bd9Sstevel@tonic-gate 			break;
606*7c478bd9Sstevel@tonic-gate 		case BIT_OR:
607*7c478bd9Sstevel@tonic-gate 			/* bitwise OR */
608*7c478bd9Sstevel@tonic-gate 			sysp->sys_op = SETOP_OR;
609*7c478bd9Sstevel@tonic-gate 			break;
610*7c478bd9Sstevel@tonic-gate 		default:
611*7c478bd9Sstevel@tonic-gate 			/* unsupported operation */
612*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file,
613*7c478bd9Sstevel@tonic-gate 			    "unsupported operator %s", tok2);
614*7c478bd9Sstevel@tonic-gate 			goto bad;
615*7c478bd9Sstevel@tonic-gate 		}
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 		switch ((tok3 = kobj_lex(file, tok1, sizeof (tok1)))) {
618*7c478bd9Sstevel@tonic-gate 		case STRING:
619*7c478bd9Sstevel@tonic-gate 			/* string variable */
620*7c478bd9Sstevel@tonic-gate 			if (sysp->sys_op != SETOP_ASSIGN) {
621*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, bad_op, tok1);
622*7c478bd9Sstevel@tonic-gate 				goto bad;
623*7c478bd9Sstevel@tonic-gate 			}
624*7c478bd9Sstevel@tonic-gate 			if (kobj_get_string(&sysp->sys_info, tok1) == 0) {
625*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, "string garbled");
626*7c478bd9Sstevel@tonic-gate 				goto bad;
627*7c478bd9Sstevel@tonic-gate 			}
628*7c478bd9Sstevel@tonic-gate 			/*
629*7c478bd9Sstevel@tonic-gate 			 * Set SYSPARAM_STR_TOKEN in sys_flags to notify
630*7c478bd9Sstevel@tonic-gate 			 * sysparam_print_warning() that this is a string
631*7c478bd9Sstevel@tonic-gate 			 * token.
632*7c478bd9Sstevel@tonic-gate 			 */
633*7c478bd9Sstevel@tonic-gate 			sysp->sys_flags |= SYSPARAM_STR_TOKEN;
634*7c478bd9Sstevel@tonic-gate 			break;
635*7c478bd9Sstevel@tonic-gate 		case HEXVAL:
636*7c478bd9Sstevel@tonic-gate 		case DECVAL:
637*7c478bd9Sstevel@tonic-gate 			if (kobj_getvalue(tok1, &sysp->sys_info) == -1) {
638*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
639*7c478bd9Sstevel@tonic-gate 				    "invalid number '%s'", tok1);
640*7c478bd9Sstevel@tonic-gate 				goto bad;
641*7c478bd9Sstevel@tonic-gate 			}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 			/*
644*7c478bd9Sstevel@tonic-gate 			 * Set the appropriate flag (hexadecimal or decimal)
645*7c478bd9Sstevel@tonic-gate 			 * in sys_flags for sysparam_print_warning() to be
646*7c478bd9Sstevel@tonic-gate 			 * able to print the number with the correct format.
647*7c478bd9Sstevel@tonic-gate 			 */
648*7c478bd9Sstevel@tonic-gate 			if (tok3 == HEXVAL) {
649*7c478bd9Sstevel@tonic-gate 				sysp->sys_flags |= SYSPARAM_HEX_TOKEN;
650*7c478bd9Sstevel@tonic-gate 			} else {
651*7c478bd9Sstevel@tonic-gate 				sysp->sys_flags |= SYSPARAM_DEC_TOKEN;
652*7c478bd9Sstevel@tonic-gate 			}
653*7c478bd9Sstevel@tonic-gate 			break;
654*7c478bd9Sstevel@tonic-gate 		default:
655*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, "bad rvalue '%s'", tok1);
656*7c478bd9Sstevel@tonic-gate 			goto bad;
657*7c478bd9Sstevel@tonic-gate 		} /* end switch */
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 		/*
660*7c478bd9Sstevel@tonic-gate 		 * Now that we've parsed it to check the syntax, consider
661*7c478bd9Sstevel@tonic-gate 		 * discarding it (because it -doesn't- apply to this flavor
662*7c478bd9Sstevel@tonic-gate 		 * of the kernel)
663*7c478bd9Sstevel@tonic-gate 		 */
664*7c478bd9Sstevel@tonic-gate #ifdef _LP64
665*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_type == MOD_SET32)
666*7c478bd9Sstevel@tonic-gate 			return (NULL);
667*7c478bd9Sstevel@tonic-gate #else
668*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_type == MOD_SET64)
669*7c478bd9Sstevel@tonic-gate 			return (NULL);
670*7c478bd9Sstevel@tonic-gate #endif
671*7c478bd9Sstevel@tonic-gate 		sysp->sys_type = MOD_SET;
672*7c478bd9Sstevel@tonic-gate 		break;
673*7c478bd9Sstevel@tonic-gate 	}
674*7c478bd9Sstevel@tonic-gate 	case MOD_MODDIR:
675*7c478bd9Sstevel@tonic-gate 		if ((token = kobj_lex(file, tok1, sizeof (tok1))) != COLON) {
676*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, colon_err, cmd);
677*7c478bd9Sstevel@tonic-gate 			goto bad;
678*7c478bd9Sstevel@tonic-gate 		}
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 		cp = tok1;
681*7c478bd9Sstevel@tonic-gate 		while ((token = kobj_lex(file, cp,
682*7c478bd9Sstevel@tonic-gate 		    sizeof (tok1) - (cp - tok1))) != NEWLINE && token != EOF) {
683*7c478bd9Sstevel@tonic-gate 			if (token == -1) {
684*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, oversize_err);
685*7c478bd9Sstevel@tonic-gate 				goto bad;
686*7c478bd9Sstevel@tonic-gate 			}
687*7c478bd9Sstevel@tonic-gate 			cp += strlen(cp);
688*7c478bd9Sstevel@tonic-gate 			while ((ch = kobj_getc(file)) != -1 && !iswhite(ch) &&
689*7c478bd9Sstevel@tonic-gate 			    !isnewline(ch) && ch != ':') {
690*7c478bd9Sstevel@tonic-gate 				if (cp - tok1 >= sizeof (tok1) - 1) {
691*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
692*7c478bd9Sstevel@tonic-gate 					    oversize_err);
693*7c478bd9Sstevel@tonic-gate 					goto bad;
694*7c478bd9Sstevel@tonic-gate 				}
695*7c478bd9Sstevel@tonic-gate 				*cp++ = (char)ch;
696*7c478bd9Sstevel@tonic-gate 			}
697*7c478bd9Sstevel@tonic-gate 			*cp = ':';
698*7c478bd9Sstevel@tonic-gate 			if (isnewline(ch))
699*7c478bd9Sstevel@tonic-gate 				(void) kobj_ungetc(file);
700*7c478bd9Sstevel@tonic-gate 		}
701*7c478bd9Sstevel@tonic-gate 		(void) kobj_ungetc(file);
702*7c478bd9Sstevel@tonic-gate 		*cp  = '\0';
703*7c478bd9Sstevel@tonic-gate 		sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(tok1) + 1,
704*7c478bd9Sstevel@tonic-gate 		    VM_SLEEP);
705*7c478bd9Sstevel@tonic-gate 		(void) strcpy(sysp->sys_ptr, tok1);
706*7c478bd9Sstevel@tonic-gate 		break;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	case MOD_SWAPDEV:
709*7c478bd9Sstevel@tonic-gate 	case MOD_ROOTDEV:
710*7c478bd9Sstevel@tonic-gate 		if ((token = kobj_lex(file, tok1, sizeof (tok1))) != COLON) {
711*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, colon_err, cmd);
712*7c478bd9Sstevel@tonic-gate 			goto bad;
713*7c478bd9Sstevel@tonic-gate 		}
714*7c478bd9Sstevel@tonic-gate 		while ((ch = kobj_getc(file)) == ' ' || ch == '\t')
715*7c478bd9Sstevel@tonic-gate 			;
716*7c478bd9Sstevel@tonic-gate 		cp = tok1;
717*7c478bd9Sstevel@tonic-gate 		while (!iswhite(ch) && !isnewline(ch) && ch != -1) {
718*7c478bd9Sstevel@tonic-gate 			if (cp - tok1 >= sizeof (tok1) - 1) {
719*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, oversize_err);
720*7c478bd9Sstevel@tonic-gate 				goto bad;
721*7c478bd9Sstevel@tonic-gate 			}
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 			*cp++ = (char)ch;
724*7c478bd9Sstevel@tonic-gate 			ch = kobj_getc(file);
725*7c478bd9Sstevel@tonic-gate 		}
726*7c478bd9Sstevel@tonic-gate 		if (ch != -1)
727*7c478bd9Sstevel@tonic-gate 			(void) kobj_ungetc(file);
728*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 		sysp->sys_ptr = vmem_alloc(mod_sysfile_arena, strlen(tok1) + 1,
731*7c478bd9Sstevel@tonic-gate 		    VM_SLEEP);
732*7c478bd9Sstevel@tonic-gate 		(void) strcpy(sysp->sys_ptr, tok1);
733*7c478bd9Sstevel@tonic-gate 		break;
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	case MOD_UNKNOWN:
736*7c478bd9Sstevel@tonic-gate 	default:
737*7c478bd9Sstevel@tonic-gate 		kobj_file_err(CE_WARN, file, "unknown command '%s'", cmd);
738*7c478bd9Sstevel@tonic-gate 		goto bad;
739*7c478bd9Sstevel@tonic-gate 	}
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	return (sysp);
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate bad:
744*7c478bd9Sstevel@tonic-gate 	kobj_find_eol(file);
745*7c478bd9Sstevel@tonic-gate 	return (NULL);
746*7c478bd9Sstevel@tonic-gate }
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate void
749*7c478bd9Sstevel@tonic-gate mod_read_system_file(int ask)
750*7c478bd9Sstevel@tonic-gate {
751*7c478bd9Sstevel@tonic-gate 	register struct sysparam *sp;
752*7c478bd9Sstevel@tonic-gate 	register struct _buf *file;
753*7c478bd9Sstevel@tonic-gate 	register token_t token, last_tok;
754*7c478bd9Sstevel@tonic-gate 	char tokval[MAXLINESIZE];
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	mod_sysfile_arena = vmem_create("mod_sysfile", NULL, 0, 8,
757*7c478bd9Sstevel@tonic-gate 	    segkmem_alloc, segkmem_free, heap_arena, 0, VM_SLEEP);
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	if (ask)
760*7c478bd9Sstevel@tonic-gate 		mod_askparams();
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	if (systemfile != NULL) {
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 		if ((file = kobj_open_file(systemfile)) ==
765*7c478bd9Sstevel@tonic-gate 		    (struct _buf *)-1) {
766*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "cannot open system file: %s",
767*7c478bd9Sstevel@tonic-gate 			    systemfile);
768*7c478bd9Sstevel@tonic-gate 		} else {
769*7c478bd9Sstevel@tonic-gate 			sysparam_tl = (struct sysparam *)&sysparam_hd;
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 			last_tok = NEWLINE;
772*7c478bd9Sstevel@tonic-gate 			while ((token = kobj_lex(file, tokval,
773*7c478bd9Sstevel@tonic-gate 			    sizeof (tokval))) != EOF) {
774*7c478bd9Sstevel@tonic-gate 				switch (token) {
775*7c478bd9Sstevel@tonic-gate 				case STAR:
776*7c478bd9Sstevel@tonic-gate 				case POUND:
777*7c478bd9Sstevel@tonic-gate 					/*
778*7c478bd9Sstevel@tonic-gate 					 * Skip comments.
779*7c478bd9Sstevel@tonic-gate 					 */
780*7c478bd9Sstevel@tonic-gate 					kobj_find_eol(file);
781*7c478bd9Sstevel@tonic-gate 					break;
782*7c478bd9Sstevel@tonic-gate 				case NEWLINE:
783*7c478bd9Sstevel@tonic-gate 					kobj_newline(file);
784*7c478bd9Sstevel@tonic-gate 					last_tok = NEWLINE;
785*7c478bd9Sstevel@tonic-gate 					break;
786*7c478bd9Sstevel@tonic-gate 				case NAME:
787*7c478bd9Sstevel@tonic-gate 					if (last_tok != NEWLINE) {
788*7c478bd9Sstevel@tonic-gate 						kobj_file_err(CE_WARN, file,
789*7c478bd9Sstevel@tonic-gate 						    extra_err, tokval);
790*7c478bd9Sstevel@tonic-gate 						kobj_find_eol(file);
791*7c478bd9Sstevel@tonic-gate 					} else if ((sp = do_sysfile_cmd(file,
792*7c478bd9Sstevel@tonic-gate 					    tokval)) != NULL) {
793*7c478bd9Sstevel@tonic-gate 						sp->sys_next = NULL;
794*7c478bd9Sstevel@tonic-gate 						sysparam_tl->sys_next = sp;
795*7c478bd9Sstevel@tonic-gate 						sysparam_tl = sp;
796*7c478bd9Sstevel@tonic-gate 					}
797*7c478bd9Sstevel@tonic-gate 					last_tok = NAME;
798*7c478bd9Sstevel@tonic-gate 					break;
799*7c478bd9Sstevel@tonic-gate 				default:
800*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN,
801*7c478bd9Sstevel@tonic-gate 					    file, tok_err, tokval);
802*7c478bd9Sstevel@tonic-gate 					kobj_find_eol(file);
803*7c478bd9Sstevel@tonic-gate 					break;
804*7c478bd9Sstevel@tonic-gate 				}
805*7c478bd9Sstevel@tonic-gate 			}
806*7c478bd9Sstevel@tonic-gate 			kobj_close_file(file);
807*7c478bd9Sstevel@tonic-gate 		}
808*7c478bd9Sstevel@tonic-gate 	}
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	/*
811*7c478bd9Sstevel@tonic-gate 	 * Sanity check of /etc/system.
812*7c478bd9Sstevel@tonic-gate 	 */
813*7c478bd9Sstevel@tonic-gate 	check_system_file();
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 	param_preset();
816*7c478bd9Sstevel@tonic-gate 	(void) mod_sysctl(SYS_SET_KVAR, NULL);
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 	if (ask == 0)
819*7c478bd9Sstevel@tonic-gate 		setparams();
820*7c478bd9Sstevel@tonic-gate }
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate /*
823*7c478bd9Sstevel@tonic-gate  * Search for a specific module variable assignment in /etc/system.  If
824*7c478bd9Sstevel@tonic-gate  * successful, 1 is returned and the value is stored in '*value'.
825*7c478bd9Sstevel@tonic-gate  * Otherwise 0 is returned and '*value' isn't modified.  If 'module' is
826*7c478bd9Sstevel@tonic-gate  * NULL we look for global definitions.
827*7c478bd9Sstevel@tonic-gate  *
828*7c478bd9Sstevel@tonic-gate  * This is useful if the value of an assignment is needed before a
829*7c478bd9Sstevel@tonic-gate  * module is loaded (e.g. to obtain a default privileged rctl limit).
830*7c478bd9Sstevel@tonic-gate  */
831*7c478bd9Sstevel@tonic-gate int
832*7c478bd9Sstevel@tonic-gate mod_sysvar(const char *module, const char *name, u_longlong_t *value)
833*7c478bd9Sstevel@tonic-gate {
834*7c478bd9Sstevel@tonic-gate 	struct sysparam	*sysp;
835*7c478bd9Sstevel@tonic-gate 	int cnt = 0; /* dummy */
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	ASSERT(name != NULL);
838*7c478bd9Sstevel@tonic-gate 	ASSERT(value != NULL);
839*7c478bd9Sstevel@tonic-gate 	for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 		if ((sysp->sys_type == MOD_SET) &&
842*7c478bd9Sstevel@tonic-gate 		    (((module == NULL) && (sysp->sys_modnam == NULL)) ||
843*7c478bd9Sstevel@tonic-gate 		    ((module != NULL) && (sysp->sys_modnam != NULL) &&
844*7c478bd9Sstevel@tonic-gate 		    (strcmp(module, sysp->sys_modnam) == 0)))) {
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 			ASSERT(sysp->sys_ptr != NULL);
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 			if (strcmp(name, sysp->sys_ptr) == 0) {
849*7c478bd9Sstevel@tonic-gate 				sysparam_count_entry(sysp, &cnt, value);
850*7c478bd9Sstevel@tonic-gate 				if ((sysp->sys_flags & SYSPARAM_TERM) != 0)
851*7c478bd9Sstevel@tonic-gate 					return (1);
852*7c478bd9Sstevel@tonic-gate 				continue;
853*7c478bd9Sstevel@tonic-gate 			}
854*7c478bd9Sstevel@tonic-gate 		}
855*7c478bd9Sstevel@tonic-gate 	}
856*7c478bd9Sstevel@tonic-gate 	ASSERT(cnt == 0);
857*7c478bd9Sstevel@tonic-gate 	return (0);
858*7c478bd9Sstevel@tonic-gate }
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate /*
861*7c478bd9Sstevel@tonic-gate  * This function scans sysparam records, which are created from the
862*7c478bd9Sstevel@tonic-gate  * contents of /etc/system, for entries which are logical duplicates,
863*7c478bd9Sstevel@tonic-gate  * and prints warning messages as appropriate.  When multiple "set"
864*7c478bd9Sstevel@tonic-gate  * commands are encountered, the pileup of values with "&", "|"
865*7c478bd9Sstevel@tonic-gate  * and "=" operators results in the final value.
866*7c478bd9Sstevel@tonic-gate  */
867*7c478bd9Sstevel@tonic-gate static void
868*7c478bd9Sstevel@tonic-gate check_system_file(void)
869*7c478bd9Sstevel@tonic-gate {
870*7c478bd9Sstevel@tonic-gate 	struct sysparam	*sysp;
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 	for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
873*7c478bd9Sstevel@tonic-gate 		struct sysparam *entry, *final;
874*7c478bd9Sstevel@tonic-gate 		u_longlong_t value = 0;
875*7c478bd9Sstevel@tonic-gate 		int cnt = 1;
876*7c478bd9Sstevel@tonic-gate 		/*
877*7c478bd9Sstevel@tonic-gate 		 * If the entry is already checked, skip it.
878*7c478bd9Sstevel@tonic-gate 		 */
879*7c478bd9Sstevel@tonic-gate 		if ((sysp->sys_flags & SYSPARAM_DUP) != 0)
880*7c478bd9Sstevel@tonic-gate 			continue;
881*7c478bd9Sstevel@tonic-gate 		/*
882*7c478bd9Sstevel@tonic-gate 		 * Check if there is a duplicate entry by doing a linear
883*7c478bd9Sstevel@tonic-gate 		 * search.
884*7c478bd9Sstevel@tonic-gate 		 */
885*7c478bd9Sstevel@tonic-gate 		final = sysp;
886*7c478bd9Sstevel@tonic-gate 		for (entry = sysp->sys_next; entry != NULL;
887*7c478bd9Sstevel@tonic-gate 		    entry = entry->sys_next) {
888*7c478bd9Sstevel@tonic-gate 			/*
889*7c478bd9Sstevel@tonic-gate 			 * Check the entry. if it's different, skip this.
890*7c478bd9Sstevel@tonic-gate 			 */
891*7c478bd9Sstevel@tonic-gate 			if (sysparam_compare_entry(sysp, entry) != 0)
892*7c478bd9Sstevel@tonic-gate 				continue;
893*7c478bd9Sstevel@tonic-gate 			/*
894*7c478bd9Sstevel@tonic-gate 			 * Count the entry and put the mark.
895*7c478bd9Sstevel@tonic-gate 			 */
896*7c478bd9Sstevel@tonic-gate 			sysparam_count_entry(entry, &cnt, &value);
897*7c478bd9Sstevel@tonic-gate 			entry->sys_flags |= SYSPARAM_DUP;
898*7c478bd9Sstevel@tonic-gate 			final = entry;
899*7c478bd9Sstevel@tonic-gate 		}
900*7c478bd9Sstevel@tonic-gate 		final->sys_flags |= SYSPARAM_TERM;
901*7c478bd9Sstevel@tonic-gate 		/*
902*7c478bd9Sstevel@tonic-gate 		 * Print the warning if it's duplicated.
903*7c478bd9Sstevel@tonic-gate 		 */
904*7c478bd9Sstevel@tonic-gate 		if (cnt >= 2)
905*7c478bd9Sstevel@tonic-gate 			sysparam_print_warning(final, value);
906*7c478bd9Sstevel@tonic-gate 	}
907*7c478bd9Sstevel@tonic-gate }
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate /*
910*7c478bd9Sstevel@tonic-gate  * Compare the sysparam records.
911*7c478bd9Sstevel@tonic-gate  * Return 0 if they are the same, return 1 if not.
912*7c478bd9Sstevel@tonic-gate  */
913*7c478bd9Sstevel@tonic-gate static int
914*7c478bd9Sstevel@tonic-gate sysparam_compare_entry(struct sysparam *sysp, struct sysparam *entry)
915*7c478bd9Sstevel@tonic-gate {
916*7c478bd9Sstevel@tonic-gate 	ASSERT(sysp->sys_ptr != NULL && entry->sys_ptr != NULL);
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 	/*
919*7c478bd9Sstevel@tonic-gate 	 * If the command is rootdev, rootfs, swapdev, swapfs or moddir,
920*7c478bd9Sstevel@tonic-gate 	 * the record with the same type is treated as a duplicate record.
921*7c478bd9Sstevel@tonic-gate 	 * In other cases, the record is treated as a duplicate record when
922*7c478bd9Sstevel@tonic-gate 	 * its type, its module name (if it exists), and its variable name
923*7c478bd9Sstevel@tonic-gate 	 * are the same.
924*7c478bd9Sstevel@tonic-gate 	 */
925*7c478bd9Sstevel@tonic-gate 	switch (sysp->sys_type) {
926*7c478bd9Sstevel@tonic-gate 	case MOD_ROOTDEV:
927*7c478bd9Sstevel@tonic-gate 	case MOD_ROOTFS:
928*7c478bd9Sstevel@tonic-gate 	case MOD_SWAPDEV:
929*7c478bd9Sstevel@tonic-gate 	case MOD_SWAPFS:
930*7c478bd9Sstevel@tonic-gate 	case MOD_MODDIR:
931*7c478bd9Sstevel@tonic-gate 		return (sysp->sys_type == entry->sys_type ? 0 : 1);
932*7c478bd9Sstevel@tonic-gate 	default: /* In other cases, just go through it. */
933*7c478bd9Sstevel@tonic-gate 		break;
934*7c478bd9Sstevel@tonic-gate 	}
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate 	if (sysp->sys_type != entry->sys_type)
937*7c478bd9Sstevel@tonic-gate 		return (1);
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	if (sysp->sys_modnam != NULL && entry->sys_modnam == NULL)
940*7c478bd9Sstevel@tonic-gate 		return (1);
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	if (sysp->sys_modnam == NULL && entry->sys_modnam != NULL)
943*7c478bd9Sstevel@tonic-gate 		return (1);
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	if (sysp->sys_modnam != NULL && entry->sys_modnam != NULL &&
946*7c478bd9Sstevel@tonic-gate 	    strcmp(sysp->sys_modnam, entry->sys_modnam) != 0)
947*7c478bd9Sstevel@tonic-gate 		return (1);
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	return (strcmp(sysp->sys_ptr, entry->sys_ptr));
950*7c478bd9Sstevel@tonic-gate }
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate /*
953*7c478bd9Sstevel@tonic-gate  * Translate a sysparam type value to a string.
954*7c478bd9Sstevel@tonic-gate  */
955*7c478bd9Sstevel@tonic-gate static char *
956*7c478bd9Sstevel@tonic-gate sysparam_type_to_str(int type)
957*7c478bd9Sstevel@tonic-gate {
958*7c478bd9Sstevel@tonic-gate 	struct modcmd *mcp;
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	for (mcp = modcmd; mcp->mc_cmdname != NULL; mcp++) {
961*7c478bd9Sstevel@tonic-gate 		if (mcp->mc_type == type)
962*7c478bd9Sstevel@tonic-gate 			break;
963*7c478bd9Sstevel@tonic-gate 	}
964*7c478bd9Sstevel@tonic-gate 	ASSERT(mcp->mc_type == type);
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	if (type != MOD_UNKNOWN)
967*7c478bd9Sstevel@tonic-gate 		return ((++mcp)->mc_cmdname); /* lower case */
968*7c478bd9Sstevel@tonic-gate 	else
969*7c478bd9Sstevel@tonic-gate 		return ("");	/* MOD_UNKNOWN */
970*7c478bd9Sstevel@tonic-gate }
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate /*
973*7c478bd9Sstevel@tonic-gate  * Check the entry and accumulate the number of entries.
974*7c478bd9Sstevel@tonic-gate  */
975*7c478bd9Sstevel@tonic-gate static void
976*7c478bd9Sstevel@tonic-gate sysparam_count_entry(struct sysparam *sysp, int *cnt, u_longlong_t *value)
977*7c478bd9Sstevel@tonic-gate {
978*7c478bd9Sstevel@tonic-gate 	u_longlong_t ul = sysp->sys_info;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	switch (sysp->sys_op) {
981*7c478bd9Sstevel@tonic-gate 	case SETOP_ASSIGN:
982*7c478bd9Sstevel@tonic-gate 		*value = ul;
983*7c478bd9Sstevel@tonic-gate 		(*cnt)++;
984*7c478bd9Sstevel@tonic-gate 		return;
985*7c478bd9Sstevel@tonic-gate 	case SETOP_AND:
986*7c478bd9Sstevel@tonic-gate 		*value &= ul;
987*7c478bd9Sstevel@tonic-gate 		return;
988*7c478bd9Sstevel@tonic-gate 	case SETOP_OR:
989*7c478bd9Sstevel@tonic-gate 		*value |= ul;
990*7c478bd9Sstevel@tonic-gate 		return;
991*7c478bd9Sstevel@tonic-gate 	default: /* Not MOD_SET */
992*7c478bd9Sstevel@tonic-gate 		(*cnt)++;
993*7c478bd9Sstevel@tonic-gate 		return;
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate }
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate /*
998*7c478bd9Sstevel@tonic-gate  * Print out the warning if multiple entries are found in the system file.
999*7c478bd9Sstevel@tonic-gate  */
1000*7c478bd9Sstevel@tonic-gate static void
1001*7c478bd9Sstevel@tonic-gate sysparam_print_warning(struct sysparam *sysp, u_longlong_t value)
1002*7c478bd9Sstevel@tonic-gate {
1003*7c478bd9Sstevel@tonic-gate 	char *modnam = sysp->sys_modnam;
1004*7c478bd9Sstevel@tonic-gate 	char *varnam = sysp->sys_ptr;
1005*7c478bd9Sstevel@tonic-gate 	int type = sysp->sys_type;
1006*7c478bd9Sstevel@tonic-gate 	char *typenam = sysparam_type_to_str(type);
1007*7c478bd9Sstevel@tonic-gate 	boolean_t str_token = ((sysp->sys_flags & SYSPARAM_STR_TOKEN) != 0);
1008*7c478bd9Sstevel@tonic-gate 	boolean_t hex_number = ((sysp->sys_flags & SYSPARAM_HEX_TOKEN) != 0);
1009*7c478bd9Sstevel@tonic-gate #define	warn_format1 " is set more than once in /%s. "
1010*7c478bd9Sstevel@tonic-gate #define	warn_format2 " applied as the current setting.\n"
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 	ASSERT(varnam != NULL);
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 	if (type == MOD_SET) {
1015*7c478bd9Sstevel@tonic-gate 		/*
1016*7c478bd9Sstevel@tonic-gate 		 * If a string token is set, print out the string
1017*7c478bd9Sstevel@tonic-gate 		 * instead of its pointer value. In other cases,
1018*7c478bd9Sstevel@tonic-gate 		 * print out the value with the appropriate format
1019*7c478bd9Sstevel@tonic-gate 		 * for a hexadecimal number or a decimal number.
1020*7c478bd9Sstevel@tonic-gate 		 */
1021*7c478bd9Sstevel@tonic-gate 		if (modnam == NULL) {
1022*7c478bd9Sstevel@tonic-gate 			if (str_token == B_TRUE) {
1023*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s" warn_format1
1024*7c478bd9Sstevel@tonic-gate 				    "\"%s %s = %s\"" warn_format2,
1025*7c478bd9Sstevel@tonic-gate 				    varnam, systemfile, typenam,
1026*7c478bd9Sstevel@tonic-gate 				    varnam, (char *)(uintptr_t)value);
1027*7c478bd9Sstevel@tonic-gate 			} else if (hex_number == B_TRUE) {
1028*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s" warn_format1
1029*7c478bd9Sstevel@tonic-gate 				    "\"%s %s = 0x%llx\"" warn_format2,
1030*7c478bd9Sstevel@tonic-gate 				    varnam, systemfile, typenam,
1031*7c478bd9Sstevel@tonic-gate 				    varnam, value);
1032*7c478bd9Sstevel@tonic-gate 			} else {
1033*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s" warn_format1
1034*7c478bd9Sstevel@tonic-gate 				    "\"%s %s = %lld\"" warn_format2,
1035*7c478bd9Sstevel@tonic-gate 				    varnam, systemfile, typenam,
1036*7c478bd9Sstevel@tonic-gate 				    varnam, value);
1037*7c478bd9Sstevel@tonic-gate 			}
1038*7c478bd9Sstevel@tonic-gate 		} else {
1039*7c478bd9Sstevel@tonic-gate 			if (str_token == B_TRUE) {
1040*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s:%s" warn_format1
1041*7c478bd9Sstevel@tonic-gate 				    "\"%s %s:%s = %s\"" warn_format2,
1042*7c478bd9Sstevel@tonic-gate 				    modnam, varnam, systemfile,
1043*7c478bd9Sstevel@tonic-gate 				    typenam, modnam, varnam,
1044*7c478bd9Sstevel@tonic-gate 				    (char *)(uintptr_t)value);
1045*7c478bd9Sstevel@tonic-gate 			} else if (hex_number == B_TRUE) {
1046*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s:%s" warn_format1
1047*7c478bd9Sstevel@tonic-gate 				    "\"%s %s:%s = 0x%llx\"" warn_format2,
1048*7c478bd9Sstevel@tonic-gate 				    modnam, varnam, systemfile,
1049*7c478bd9Sstevel@tonic-gate 				    typenam, modnam, varnam, value);
1050*7c478bd9Sstevel@tonic-gate 			} else {
1051*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s:%s" warn_format1
1052*7c478bd9Sstevel@tonic-gate 				    "\"%s %s:%s = %lld\"" warn_format2,
1053*7c478bd9Sstevel@tonic-gate 				    modnam, varnam, systemfile,
1054*7c478bd9Sstevel@tonic-gate 				    typenam, modnam, varnam, value);
1055*7c478bd9Sstevel@tonic-gate 			}
1056*7c478bd9Sstevel@tonic-gate 		}
1057*7c478bd9Sstevel@tonic-gate 	} else {
1058*7c478bd9Sstevel@tonic-gate 		/*
1059*7c478bd9Sstevel@tonic-gate 		 * If the type is MOD_ROOTDEV, MOD_ROOTFS, MOD_SWAPDEV,
1060*7c478bd9Sstevel@tonic-gate 		 * MOD_SWAPFS or MOD_MODDIR, the entry is treated as
1061*7c478bd9Sstevel@tonic-gate 		 * a duplicate one if it has the same type regardless
1062*7c478bd9Sstevel@tonic-gate 		 * of its variable name.
1063*7c478bd9Sstevel@tonic-gate 		 */
1064*7c478bd9Sstevel@tonic-gate 		switch (type) {
1065*7c478bd9Sstevel@tonic-gate 		case MOD_ROOTDEV:
1066*7c478bd9Sstevel@tonic-gate 		case MOD_ROOTFS:
1067*7c478bd9Sstevel@tonic-gate 		case MOD_SWAPDEV:
1068*7c478bd9Sstevel@tonic-gate 		case MOD_SWAPFS:
1069*7c478bd9Sstevel@tonic-gate 		case MOD_MODDIR:
1070*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "\"%s\" appears more than once "
1071*7c478bd9Sstevel@tonic-gate 			    "in /%s.", typenam, systemfile);
1072*7c478bd9Sstevel@tonic-gate 			break;
1073*7c478bd9Sstevel@tonic-gate 		default:
1074*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "\"%s: %s\" appears more than once "
1075*7c478bd9Sstevel@tonic-gate 			    "in /%s.", typenam, varnam, systemfile);
1076*7c478bd9Sstevel@tonic-gate 			break;
1077*7c478bd9Sstevel@tonic-gate 		}
1078*7c478bd9Sstevel@tonic-gate 	}
1079*7c478bd9Sstevel@tonic-gate }
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate /*
1082*7c478bd9Sstevel@tonic-gate  * Process the system file commands.
1083*7c478bd9Sstevel@tonic-gate  */
1084*7c478bd9Sstevel@tonic-gate int
1085*7c478bd9Sstevel@tonic-gate mod_sysctl(int fcn, void *p)
1086*7c478bd9Sstevel@tonic-gate {
1087*7c478bd9Sstevel@tonic-gate 	static char wmesg[] = "forceload of %s failed";
1088*7c478bd9Sstevel@tonic-gate 	struct sysparam *sysp;
1089*7c478bd9Sstevel@tonic-gate 	char *name;
1090*7c478bd9Sstevel@tonic-gate 	struct modctl *modp;
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	if (sysparam_hd == NULL)
1093*7c478bd9Sstevel@tonic-gate 		return (0);
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 		switch (fcn) {
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 		case SYS_FORCELOAD:
1100*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_type == MOD_FORCELOAD) {
1101*7c478bd9Sstevel@tonic-gate 			name = sysp->sys_ptr;
1102*7c478bd9Sstevel@tonic-gate 			if (modload(NULL, name) == -1)
1103*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, wmesg, name);
1104*7c478bd9Sstevel@tonic-gate 			/*
1105*7c478bd9Sstevel@tonic-gate 			 * The following works because it
1106*7c478bd9Sstevel@tonic-gate 			 * runs before autounloading is started!!
1107*7c478bd9Sstevel@tonic-gate 			 */
1108*7c478bd9Sstevel@tonic-gate 			modp = mod_find_by_filename(NULL, name);
1109*7c478bd9Sstevel@tonic-gate 			if (modp != NULL)
1110*7c478bd9Sstevel@tonic-gate 				modp->mod_loadflags |= MOD_NOAUTOUNLOAD;
1111*7c478bd9Sstevel@tonic-gate 			/*
1112*7c478bd9Sstevel@tonic-gate 			 * For drivers, attempt to install it.
1113*7c478bd9Sstevel@tonic-gate 			 */
1114*7c478bd9Sstevel@tonic-gate 			if (strncmp(sysp->sys_ptr, "drv", 3) == 0) {
1115*7c478bd9Sstevel@tonic-gate 				(void) ddi_install_driver(name + 4);
1116*7c478bd9Sstevel@tonic-gate 			}
1117*7c478bd9Sstevel@tonic-gate 		}
1118*7c478bd9Sstevel@tonic-gate 		break;
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 		case SYS_SET_KVAR:
1121*7c478bd9Sstevel@tonic-gate 		case SYS_SET_MVAR:
1122*7c478bd9Sstevel@tonic-gate 			if (sysp->sys_type == MOD_SET)
1123*7c478bd9Sstevel@tonic-gate 				sys_set_var(fcn, sysp, p);
1124*7c478bd9Sstevel@tonic-gate 			break;
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 		case SYS_CHECK_EXCLUDE:
1127*7c478bd9Sstevel@tonic-gate 			if (sysp->sys_type == MOD_EXCLUDE) {
1128*7c478bd9Sstevel@tonic-gate 				if (p == NULL || sysp->sys_ptr == NULL)
1129*7c478bd9Sstevel@tonic-gate 					return (0);
1130*7c478bd9Sstevel@tonic-gate 				if (strcmp((char *)p, sysp->sys_ptr) == 0)
1131*7c478bd9Sstevel@tonic-gate 					return (1);
1132*7c478bd9Sstevel@tonic-gate 			}
1133*7c478bd9Sstevel@tonic-gate 		}
1134*7c478bd9Sstevel@tonic-gate 	}
1135*7c478bd9Sstevel@tonic-gate 	param_check();
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 	return (0);
1138*7c478bd9Sstevel@tonic-gate }
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate /*
1141*7c478bd9Sstevel@tonic-gate  * Process the system file commands, by type.
1142*7c478bd9Sstevel@tonic-gate  */
1143*7c478bd9Sstevel@tonic-gate int
1144*7c478bd9Sstevel@tonic-gate mod_sysctl_type(int type, int (*func)(struct sysparam *, void *), void *p)
1145*7c478bd9Sstevel@tonic-gate {
1146*7c478bd9Sstevel@tonic-gate 	struct sysparam *sysp;
1147*7c478bd9Sstevel@tonic-gate 	int	err;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 	for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next)
1150*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_type == type)
1151*7c478bd9Sstevel@tonic-gate 			if (err = (*(func))(sysp, p))
1152*7c478bd9Sstevel@tonic-gate 				return (err);
1153*7c478bd9Sstevel@tonic-gate 	return (0);
1154*7c478bd9Sstevel@tonic-gate }
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate static char seterr[] = "Symbol %s has size of 0 in symbol table. %s";
1158*7c478bd9Sstevel@tonic-gate static char assumption[] = "Assuming it is an 'int'";
1159*7c478bd9Sstevel@tonic-gate static char defmsg[] = "Trying to set a variable that is of size %d";
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate static void set_int8_var(uintptr_t, struct sysparam *);
1162*7c478bd9Sstevel@tonic-gate static void set_int16_var(uintptr_t, struct sysparam *);
1163*7c478bd9Sstevel@tonic-gate static void set_int32_var(uintptr_t, struct sysparam *);
1164*7c478bd9Sstevel@tonic-gate static void set_int64_var(uintptr_t, struct sysparam *);
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate static void
1167*7c478bd9Sstevel@tonic-gate sys_set_var(int fcn, struct sysparam *sysp, void *p)
1168*7c478bd9Sstevel@tonic-gate {
1169*7c478bd9Sstevel@tonic-gate 	uintptr_t symaddr;
1170*7c478bd9Sstevel@tonic-gate 	int size;
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	if (fcn == SYS_SET_KVAR && sysp->sys_modnam == NULL) {
1173*7c478bd9Sstevel@tonic-gate 		symaddr = kobj_getelfsym(sysp->sys_ptr, NULL, &size);
1174*7c478bd9Sstevel@tonic-gate 	} else if (fcn == SYS_SET_MVAR) {
1175*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_modnam == (char *)NULL ||
1176*7c478bd9Sstevel@tonic-gate 			strcmp(((struct modctl *)p)->mod_modname,
1177*7c478bd9Sstevel@tonic-gate 			    sysp->sys_modnam) != 0)
1178*7c478bd9Sstevel@tonic-gate 				return;
1179*7c478bd9Sstevel@tonic-gate 		symaddr = kobj_getelfsym(sysp->sys_ptr,
1180*7c478bd9Sstevel@tonic-gate 		    ((struct modctl *)p)->mod_mp, &size);
1181*7c478bd9Sstevel@tonic-gate 	} else
1182*7c478bd9Sstevel@tonic-gate 		return;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	if (symaddr != NULL) {
1185*7c478bd9Sstevel@tonic-gate 		switch (size) {
1186*7c478bd9Sstevel@tonic-gate 		case 1:
1187*7c478bd9Sstevel@tonic-gate 			set_int8_var(symaddr, sysp);
1188*7c478bd9Sstevel@tonic-gate 			break;
1189*7c478bd9Sstevel@tonic-gate 		case 2:
1190*7c478bd9Sstevel@tonic-gate 			set_int16_var(symaddr, sysp);
1191*7c478bd9Sstevel@tonic-gate 			break;
1192*7c478bd9Sstevel@tonic-gate 		case 0:
1193*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, seterr, sysp->sys_ptr, assumption);
1194*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
1195*7c478bd9Sstevel@tonic-gate 		case 4:
1196*7c478bd9Sstevel@tonic-gate 			set_int32_var(symaddr, sysp);
1197*7c478bd9Sstevel@tonic-gate 			break;
1198*7c478bd9Sstevel@tonic-gate 		case 8:
1199*7c478bd9Sstevel@tonic-gate 			set_int64_var(symaddr, sysp);
1200*7c478bd9Sstevel@tonic-gate 			break;
1201*7c478bd9Sstevel@tonic-gate 		default:
1202*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, defmsg, size);
1203*7c478bd9Sstevel@tonic-gate 			break;
1204*7c478bd9Sstevel@tonic-gate 		}
1205*7c478bd9Sstevel@tonic-gate 	} else {
1206*7c478bd9Sstevel@tonic-gate 		printf("sorry, variable '%s' is not defined in the '%s' ",
1207*7c478bd9Sstevel@tonic-gate 		    sysp->sys_ptr,
1208*7c478bd9Sstevel@tonic-gate 		    sysp->sys_modnam ? sysp->sys_modnam : "kernel");
1209*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_modnam)
1210*7c478bd9Sstevel@tonic-gate 			printf("module");
1211*7c478bd9Sstevel@tonic-gate 		printf("\n");
1212*7c478bd9Sstevel@tonic-gate 	}
1213*7c478bd9Sstevel@tonic-gate }
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate static void
1216*7c478bd9Sstevel@tonic-gate set_int8_var(uintptr_t symaddr, struct sysparam *sysp)
1217*7c478bd9Sstevel@tonic-gate {
1218*7c478bd9Sstevel@tonic-gate 	uint8_t uc = (uint8_t)sysp->sys_info;
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1221*7c478bd9Sstevel@tonic-gate 		printf("OP: %x: param '%s' was '0x%" PRIx8
1222*7c478bd9Sstevel@tonic-gate 		    "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1223*7c478bd9Sstevel@tonic-gate 		    *(uint8_t *)symaddr, sysp->sys_modnam);
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 	switch (sysp->sys_op) {
1226*7c478bd9Sstevel@tonic-gate 	case SETOP_ASSIGN:
1227*7c478bd9Sstevel@tonic-gate 		*(uint8_t *)symaddr = uc;
1228*7c478bd9Sstevel@tonic-gate 		break;
1229*7c478bd9Sstevel@tonic-gate 	case SETOP_AND:
1230*7c478bd9Sstevel@tonic-gate 		*(uint8_t *)symaddr &= uc;
1231*7c478bd9Sstevel@tonic-gate 		break;
1232*7c478bd9Sstevel@tonic-gate 	case SETOP_OR:
1233*7c478bd9Sstevel@tonic-gate 		*(uint8_t *)symaddr |= uc;
1234*7c478bd9Sstevel@tonic-gate 		break;
1235*7c478bd9Sstevel@tonic-gate 	}
1236*7c478bd9Sstevel@tonic-gate 
1237*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1238*7c478bd9Sstevel@tonic-gate 		printf("now it is set to '0x%" PRIx8 "'.\n",
1239*7c478bd9Sstevel@tonic-gate 		    *(uint8_t *)symaddr);
1240*7c478bd9Sstevel@tonic-gate }
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate static void
1243*7c478bd9Sstevel@tonic-gate set_int16_var(uintptr_t symaddr, struct sysparam *sysp)
1244*7c478bd9Sstevel@tonic-gate {
1245*7c478bd9Sstevel@tonic-gate 	uint16_t us = (uint16_t)sysp->sys_info;
1246*7c478bd9Sstevel@tonic-gate 
1247*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1248*7c478bd9Sstevel@tonic-gate 		printf("OP: %x: param '%s' was '0x%" PRIx16
1249*7c478bd9Sstevel@tonic-gate 		    "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1250*7c478bd9Sstevel@tonic-gate 		    *(uint16_t *)symaddr, sysp->sys_modnam);
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	switch (sysp->sys_op) {
1253*7c478bd9Sstevel@tonic-gate 	case SETOP_ASSIGN:
1254*7c478bd9Sstevel@tonic-gate 		*(uint16_t *)symaddr = us;
1255*7c478bd9Sstevel@tonic-gate 		break;
1256*7c478bd9Sstevel@tonic-gate 	case SETOP_AND:
1257*7c478bd9Sstevel@tonic-gate 		*(uint16_t *)symaddr &= us;
1258*7c478bd9Sstevel@tonic-gate 		break;
1259*7c478bd9Sstevel@tonic-gate 	case SETOP_OR:
1260*7c478bd9Sstevel@tonic-gate 		*(uint16_t *)symaddr |= us;
1261*7c478bd9Sstevel@tonic-gate 		break;
1262*7c478bd9Sstevel@tonic-gate 	}
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1265*7c478bd9Sstevel@tonic-gate 		printf("now it is set to '0x%" PRIx16 "'.\n",
1266*7c478bd9Sstevel@tonic-gate 		    *(uint16_t *)symaddr);
1267*7c478bd9Sstevel@tonic-gate }
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate static void
1270*7c478bd9Sstevel@tonic-gate set_int32_var(uintptr_t symaddr, struct sysparam *sysp)
1271*7c478bd9Sstevel@tonic-gate {
1272*7c478bd9Sstevel@tonic-gate 	uint32_t ui = (uint32_t)sysp->sys_info;
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1275*7c478bd9Sstevel@tonic-gate 		printf("OP: %x: param '%s' was '0x%" PRIx32
1276*7c478bd9Sstevel@tonic-gate 		    "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1277*7c478bd9Sstevel@tonic-gate 		    *(uint32_t *)symaddr, sysp->sys_modnam);
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 	switch (sysp->sys_op) {
1280*7c478bd9Sstevel@tonic-gate 	case SETOP_ASSIGN:
1281*7c478bd9Sstevel@tonic-gate 		*(uint32_t *)symaddr = ui;
1282*7c478bd9Sstevel@tonic-gate 		break;
1283*7c478bd9Sstevel@tonic-gate 	case SETOP_AND:
1284*7c478bd9Sstevel@tonic-gate 		*(uint32_t *)symaddr &= ui;
1285*7c478bd9Sstevel@tonic-gate 		break;
1286*7c478bd9Sstevel@tonic-gate 	case SETOP_OR:
1287*7c478bd9Sstevel@tonic-gate 		*(uint32_t *)symaddr |= ui;
1288*7c478bd9Sstevel@tonic-gate 		break;
1289*7c478bd9Sstevel@tonic-gate 	}
1290*7c478bd9Sstevel@tonic-gate 
1291*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1292*7c478bd9Sstevel@tonic-gate 		printf("now it is set to '0x%" PRIx32 "'.\n",
1293*7c478bd9Sstevel@tonic-gate 		    *(uint32_t *)symaddr);
1294*7c478bd9Sstevel@tonic-gate }
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate static void
1297*7c478bd9Sstevel@tonic-gate set_int64_var(uintptr_t symaddr, struct sysparam *sysp)
1298*7c478bd9Sstevel@tonic-gate {
1299*7c478bd9Sstevel@tonic-gate 	uint64_t ul = sysp->sys_info;
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1302*7c478bd9Sstevel@tonic-gate 		printf("OP: %x: param '%s' was '0x%" PRIx64
1303*7c478bd9Sstevel@tonic-gate 		    "' in module: '%s'.\n", sysp->sys_op, sysp->sys_ptr,
1304*7c478bd9Sstevel@tonic-gate 		    *(uint64_t *)symaddr, sysp->sys_modnam);
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate 	switch (sysp->sys_op) {
1307*7c478bd9Sstevel@tonic-gate 	case SETOP_ASSIGN:
1308*7c478bd9Sstevel@tonic-gate 		*(uint64_t *)symaddr = ul;
1309*7c478bd9Sstevel@tonic-gate 		break;
1310*7c478bd9Sstevel@tonic-gate 	case SETOP_AND:
1311*7c478bd9Sstevel@tonic-gate 		*(uint64_t *)symaddr &= ul;
1312*7c478bd9Sstevel@tonic-gate 		break;
1313*7c478bd9Sstevel@tonic-gate 	case SETOP_OR:
1314*7c478bd9Sstevel@tonic-gate 		*(uint64_t *)symaddr |= ul;
1315*7c478bd9Sstevel@tonic-gate 		break;
1316*7c478bd9Sstevel@tonic-gate 	}
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 	if (moddebug & MODDEBUG_LOADMSG)
1319*7c478bd9Sstevel@tonic-gate 		printf("now it is set to '0x%" PRIx64 "'.\n",
1320*7c478bd9Sstevel@tonic-gate 		    *(uint64_t *)symaddr);
1321*7c478bd9Sstevel@tonic-gate }
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate /*
1324*7c478bd9Sstevel@tonic-gate  * The next item on the line is a string value. Allocate memory for
1325*7c478bd9Sstevel@tonic-gate  * it and copy the string. Return 1, and set arg ptr to newly allocated
1326*7c478bd9Sstevel@tonic-gate  * and initialized buffer, or NULL if an error occurs.
1327*7c478bd9Sstevel@tonic-gate  */
1328*7c478bd9Sstevel@tonic-gate int
1329*7c478bd9Sstevel@tonic-gate kobj_get_string(u_longlong_t *llptr, char *tchar)
1330*7c478bd9Sstevel@tonic-gate {
1331*7c478bd9Sstevel@tonic-gate 	char *cp;
1332*7c478bd9Sstevel@tonic-gate 	char *start = (char *)0;
1333*7c478bd9Sstevel@tonic-gate 	int len = 0;
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 	len = strlen(tchar);
1336*7c478bd9Sstevel@tonic-gate 	start = tchar;
1337*7c478bd9Sstevel@tonic-gate 	/* copy string */
1338*7c478bd9Sstevel@tonic-gate 	cp = vmem_alloc(mod_sysfile_arena, len + 1, VM_SLEEP);
1339*7c478bd9Sstevel@tonic-gate 	bzero(cp, len + 1);
1340*7c478bd9Sstevel@tonic-gate 	*llptr = (u_longlong_t)(uintptr_t)cp;
1341*7c478bd9Sstevel@tonic-gate 	for (; len > 0; len--) {
1342*7c478bd9Sstevel@tonic-gate 		/* convert some common escape sequences */
1343*7c478bd9Sstevel@tonic-gate 		if (*start == '\\') {
1344*7c478bd9Sstevel@tonic-gate 			switch (*(start + 1)) {
1345*7c478bd9Sstevel@tonic-gate 			case 't':
1346*7c478bd9Sstevel@tonic-gate 				/* tab */
1347*7c478bd9Sstevel@tonic-gate 				*cp++ = '\t';
1348*7c478bd9Sstevel@tonic-gate 				len--;
1349*7c478bd9Sstevel@tonic-gate 				start += 2;
1350*7c478bd9Sstevel@tonic-gate 				break;
1351*7c478bd9Sstevel@tonic-gate 			case 'n':
1352*7c478bd9Sstevel@tonic-gate 				/* new line */
1353*7c478bd9Sstevel@tonic-gate 				*cp++ = '\n';
1354*7c478bd9Sstevel@tonic-gate 				len--;
1355*7c478bd9Sstevel@tonic-gate 				start += 2;
1356*7c478bd9Sstevel@tonic-gate 				break;
1357*7c478bd9Sstevel@tonic-gate 			case 'b':
1358*7c478bd9Sstevel@tonic-gate 				/* back space */
1359*7c478bd9Sstevel@tonic-gate 				*cp++ = '\b';
1360*7c478bd9Sstevel@tonic-gate 				len--;
1361*7c478bd9Sstevel@tonic-gate 				start += 2;
1362*7c478bd9Sstevel@tonic-gate 				break;
1363*7c478bd9Sstevel@tonic-gate 			default:
1364*7c478bd9Sstevel@tonic-gate 				/* simply copy it */
1365*7c478bd9Sstevel@tonic-gate 				*cp++ = *start++;
1366*7c478bd9Sstevel@tonic-gate 				break;
1367*7c478bd9Sstevel@tonic-gate 			}
1368*7c478bd9Sstevel@tonic-gate 		} else
1369*7c478bd9Sstevel@tonic-gate 			*cp++ = *start++;
1370*7c478bd9Sstevel@tonic-gate 	}
1371*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
1372*7c478bd9Sstevel@tonic-gate 	return (1);
1373*7c478bd9Sstevel@tonic-gate }
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate /*
1377*7c478bd9Sstevel@tonic-gate  * this function frees the memory allocated by kobj_get_string
1378*7c478bd9Sstevel@tonic-gate  */
1379*7c478bd9Sstevel@tonic-gate void
1380*7c478bd9Sstevel@tonic-gate kobj_free_string(void *ptr, int len)
1381*7c478bd9Sstevel@tonic-gate {
1382*7c478bd9Sstevel@tonic-gate 	vmem_free(mod_sysfile_arena, ptr, len);
1383*7c478bd9Sstevel@tonic-gate }
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 
1386*7c478bd9Sstevel@tonic-gate /*
1387*7c478bd9Sstevel@tonic-gate  * get a decimal octal or hex number. Handle '~' for one's complement.
1388*7c478bd9Sstevel@tonic-gate  */
1389*7c478bd9Sstevel@tonic-gate int
1390*7c478bd9Sstevel@tonic-gate kobj_getvalue(const char *token, u_longlong_t *valuep)
1391*7c478bd9Sstevel@tonic-gate {
1392*7c478bd9Sstevel@tonic-gate 	int radix;
1393*7c478bd9Sstevel@tonic-gate 	u_longlong_t retval = 0;
1394*7c478bd9Sstevel@tonic-gate 	int onescompl = 0;
1395*7c478bd9Sstevel@tonic-gate 	int negate = 0;
1396*7c478bd9Sstevel@tonic-gate 	char c;
1397*7c478bd9Sstevel@tonic-gate 
1398*7c478bd9Sstevel@tonic-gate 	if (*token == '~') {
1399*7c478bd9Sstevel@tonic-gate 		onescompl++; /* perform one's complement on result */
1400*7c478bd9Sstevel@tonic-gate 		token++;
1401*7c478bd9Sstevel@tonic-gate 	} else if (*token == '-') {
1402*7c478bd9Sstevel@tonic-gate 		negate++;
1403*7c478bd9Sstevel@tonic-gate 		token++;
1404*7c478bd9Sstevel@tonic-gate 	}
1405*7c478bd9Sstevel@tonic-gate 	if (*token == '0') {
1406*7c478bd9Sstevel@tonic-gate 		token++;
1407*7c478bd9Sstevel@tonic-gate 		c = *token;
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 		if (c == '\0') {
1410*7c478bd9Sstevel@tonic-gate 			*valuep = 0;	/* value is 0 */
1411*7c478bd9Sstevel@tonic-gate 			return (0);
1412*7c478bd9Sstevel@tonic-gate 		}
1413*7c478bd9Sstevel@tonic-gate 
1414*7c478bd9Sstevel@tonic-gate 		if (c == 'x' || c == 'X') {
1415*7c478bd9Sstevel@tonic-gate 			radix = 16;
1416*7c478bd9Sstevel@tonic-gate 			token++;
1417*7c478bd9Sstevel@tonic-gate 		} else
1418*7c478bd9Sstevel@tonic-gate 			radix = 8;
1419*7c478bd9Sstevel@tonic-gate 	} else
1420*7c478bd9Sstevel@tonic-gate 		radix = 10;
1421*7c478bd9Sstevel@tonic-gate 
1422*7c478bd9Sstevel@tonic-gate 	while ((c = *token++)) {
1423*7c478bd9Sstevel@tonic-gate 		switch (radix) {
1424*7c478bd9Sstevel@tonic-gate 		case 8:
1425*7c478bd9Sstevel@tonic-gate 			if (c >= '0' && c <= '7')
1426*7c478bd9Sstevel@tonic-gate 				c -= '0';
1427*7c478bd9Sstevel@tonic-gate 			else
1428*7c478bd9Sstevel@tonic-gate 				return (-1);	/* invalid number */
1429*7c478bd9Sstevel@tonic-gate 			retval = (retval << 3) + c;
1430*7c478bd9Sstevel@tonic-gate 			break;
1431*7c478bd9Sstevel@tonic-gate 		case 10:
1432*7c478bd9Sstevel@tonic-gate 			if (c >= '0' && c <= '9')
1433*7c478bd9Sstevel@tonic-gate 				c -= '0';
1434*7c478bd9Sstevel@tonic-gate 			else
1435*7c478bd9Sstevel@tonic-gate 				return (-1);	/* invalid number */
1436*7c478bd9Sstevel@tonic-gate 			retval = (retval * 10) + c;
1437*7c478bd9Sstevel@tonic-gate 			break;
1438*7c478bd9Sstevel@tonic-gate 		case 16:
1439*7c478bd9Sstevel@tonic-gate 			if (c >= 'a' && c <= 'f')
1440*7c478bd9Sstevel@tonic-gate 				c = c - 'a' + 10;
1441*7c478bd9Sstevel@tonic-gate 			else if (c >= 'A' && c <= 'F')
1442*7c478bd9Sstevel@tonic-gate 				c = c - 'A' + 10;
1443*7c478bd9Sstevel@tonic-gate 			else if (c >= '0' && c <= '9')
1444*7c478bd9Sstevel@tonic-gate 				c -= '0';
1445*7c478bd9Sstevel@tonic-gate 			else
1446*7c478bd9Sstevel@tonic-gate 				return (-1);	/* invalid number */
1447*7c478bd9Sstevel@tonic-gate 			retval = (retval << 4) + c;
1448*7c478bd9Sstevel@tonic-gate 			break;
1449*7c478bd9Sstevel@tonic-gate 		}
1450*7c478bd9Sstevel@tonic-gate 	}
1451*7c478bd9Sstevel@tonic-gate 	if (onescompl)
1452*7c478bd9Sstevel@tonic-gate 		retval = ~retval;
1453*7c478bd9Sstevel@tonic-gate 	if (negate)
1454*7c478bd9Sstevel@tonic-gate 		retval = -retval;
1455*7c478bd9Sstevel@tonic-gate 	*valuep = retval;
1456*7c478bd9Sstevel@tonic-gate 	return (0);
1457*7c478bd9Sstevel@tonic-gate }
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate /*
1460*7c478bd9Sstevel@tonic-gate  * Path to the root device and root filesystem type from
1461*7c478bd9Sstevel@tonic-gate  * property information derived from the boot subsystem
1462*7c478bd9Sstevel@tonic-gate  */
1463*7c478bd9Sstevel@tonic-gate void
1464*7c478bd9Sstevel@tonic-gate setbootpath(char *path)
1465*7c478bd9Sstevel@tonic-gate {
1466*7c478bd9Sstevel@tonic-gate 	rootfs.bo_flags |= BO_VALID;
1467*7c478bd9Sstevel@tonic-gate 	(void) copystr(path, rootfs.bo_name, BO_MAXOBJNAME, NULL);
1468*7c478bd9Sstevel@tonic-gate 	BMDPRINTF(("rootfs bootpath: %s\n", rootfs.bo_name));
1469*7c478bd9Sstevel@tonic-gate }
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate void
1472*7c478bd9Sstevel@tonic-gate setbootfstype(char *fstype)
1473*7c478bd9Sstevel@tonic-gate {
1474*7c478bd9Sstevel@tonic-gate 	(void) copystr(fstype, rootfs.bo_fstype, BO_MAXFSNAME, NULL);
1475*7c478bd9Sstevel@tonic-gate 	BMDPRINTF(("rootfs fstype: %s\n", rootfs.bo_fstype));
1476*7c478bd9Sstevel@tonic-gate }
1477*7c478bd9Sstevel@tonic-gate 
1478*7c478bd9Sstevel@tonic-gate /*
1479*7c478bd9Sstevel@tonic-gate  * set parameters that can be set early during initialization.
1480*7c478bd9Sstevel@tonic-gate  */
1481*7c478bd9Sstevel@tonic-gate static void
1482*7c478bd9Sstevel@tonic-gate setparams()
1483*7c478bd9Sstevel@tonic-gate {
1484*7c478bd9Sstevel@tonic-gate 	struct sysparam *sysp;
1485*7c478bd9Sstevel@tonic-gate 	struct bootobj *bootobjp;
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate 	for (sysp = sysparam_hd; sysp != NULL; sysp = sysp->sys_next) {
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_type == MOD_MODDIR) {
1490*7c478bd9Sstevel@tonic-gate 			default_path = sysp->sys_ptr;
1491*7c478bd9Sstevel@tonic-gate 			continue;
1492*7c478bd9Sstevel@tonic-gate 		}
1493*7c478bd9Sstevel@tonic-gate 
1494*7c478bd9Sstevel@tonic-gate 		if (sysp->sys_type == MOD_SWAPDEV ||
1495*7c478bd9Sstevel@tonic-gate 		    sysp->sys_type == MOD_SWAPFS)
1496*7c478bd9Sstevel@tonic-gate 			bootobjp = &swapfile;
1497*7c478bd9Sstevel@tonic-gate 		else if (sysp->sys_type == MOD_ROOTFS)
1498*7c478bd9Sstevel@tonic-gate 			bootobjp = &rootfs;
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 		switch (sysp->sys_type) {
1501*7c478bd9Sstevel@tonic-gate 		case MOD_ROOTDEV:
1502*7c478bd9Sstevel@tonic-gate 			root_is_svm = 1;
1503*7c478bd9Sstevel@tonic-gate 			(void) copystr(sysp->sys_ptr, svm_bootpath,
1504*7c478bd9Sstevel@tonic-gate 			    BO_MAXOBJNAME, NULL);
1505*7c478bd9Sstevel@tonic-gate 			break;
1506*7c478bd9Sstevel@tonic-gate 		case MOD_SWAPDEV:
1507*7c478bd9Sstevel@tonic-gate 			bootobjp->bo_flags |= BO_VALID;
1508*7c478bd9Sstevel@tonic-gate 			(void) copystr(sysp->sys_ptr, bootobjp->bo_name,
1509*7c478bd9Sstevel@tonic-gate 			    BO_MAXOBJNAME, NULL);
1510*7c478bd9Sstevel@tonic-gate 			break;
1511*7c478bd9Sstevel@tonic-gate 		case MOD_ROOTFS:
1512*7c478bd9Sstevel@tonic-gate 		case MOD_SWAPFS:
1513*7c478bd9Sstevel@tonic-gate 			bootobjp->bo_flags |= BO_VALID;
1514*7c478bd9Sstevel@tonic-gate 			(void) copystr(sysp->sys_ptr, bootobjp->bo_fstype,
1515*7c478bd9Sstevel@tonic-gate 			    BO_MAXOBJNAME, NULL);
1516*7c478bd9Sstevel@tonic-gate 			break;
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 		default:
1519*7c478bd9Sstevel@tonic-gate 			break;
1520*7c478bd9Sstevel@tonic-gate 		}
1521*7c478bd9Sstevel@tonic-gate 	}
1522*7c478bd9Sstevel@tonic-gate }
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate /*
1525*7c478bd9Sstevel@tonic-gate  * clean up after an error.
1526*7c478bd9Sstevel@tonic-gate  */
1527*7c478bd9Sstevel@tonic-gate static void
1528*7c478bd9Sstevel@tonic-gate hwc_free(struct hwc_spec *hwcp)
1529*7c478bd9Sstevel@tonic-gate {
1530*7c478bd9Sstevel@tonic-gate 	char *name;
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate 	if ((name = hwcp->hwc_parent_name) != NULL)
1533*7c478bd9Sstevel@tonic-gate 		kmem_free(name, strlen(name) + 1);
1534*7c478bd9Sstevel@tonic-gate 	if ((name = hwcp->hwc_class_name) != NULL)
1535*7c478bd9Sstevel@tonic-gate 		kmem_free(name, strlen(name) + 1);
1536*7c478bd9Sstevel@tonic-gate 	if ((name = hwcp->hwc_devi_name) != NULL)
1537*7c478bd9Sstevel@tonic-gate 		kmem_free(name, strlen(name) + 1);
1538*7c478bd9Sstevel@tonic-gate 	i_ddi_prop_list_delete(hwcp->hwc_devi_sys_prop_ptr);
1539*7c478bd9Sstevel@tonic-gate 	kmem_free(hwcp, sizeof (struct hwc_spec));
1540*7c478bd9Sstevel@tonic-gate }
1541*7c478bd9Sstevel@tonic-gate 
1542*7c478bd9Sstevel@tonic-gate /*
1543*7c478bd9Sstevel@tonic-gate  * Free a list of specs
1544*7c478bd9Sstevel@tonic-gate  */
1545*7c478bd9Sstevel@tonic-gate void
1546*7c478bd9Sstevel@tonic-gate hwc_free_spec_list(struct hwc_spec *list)
1547*7c478bd9Sstevel@tonic-gate {
1548*7c478bd9Sstevel@tonic-gate 	while (list) {
1549*7c478bd9Sstevel@tonic-gate 		struct hwc_spec *tmp = list;
1550*7c478bd9Sstevel@tonic-gate 		list = tmp->hwc_next;
1551*7c478bd9Sstevel@tonic-gate 		hwc_free(tmp);
1552*7c478bd9Sstevel@tonic-gate 	}
1553*7c478bd9Sstevel@tonic-gate }
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate struct val_list {
1556*7c478bd9Sstevel@tonic-gate 	struct val_list *val_next;
1557*7c478bd9Sstevel@tonic-gate 	int		val_type;
1558*7c478bd9Sstevel@tonic-gate 	int		val_size;
1559*7c478bd9Sstevel@tonic-gate 	union {
1560*7c478bd9Sstevel@tonic-gate 		char *string;
1561*7c478bd9Sstevel@tonic-gate 		int integer;
1562*7c478bd9Sstevel@tonic-gate 	} val;
1563*7c478bd9Sstevel@tonic-gate };
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate static void
1566*7c478bd9Sstevel@tonic-gate add_val(struct val_list **val_listp, int val_type, caddr_t val)
1567*7c478bd9Sstevel@tonic-gate {
1568*7c478bd9Sstevel@tonic-gate 	struct val_list *new_val, *listp = *val_listp;
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 	new_val = kmem_alloc(sizeof (struct val_list), KM_SLEEP);
1571*7c478bd9Sstevel@tonic-gate 	new_val->val_next = NULL;
1572*7c478bd9Sstevel@tonic-gate 	if ((new_val->val_type = val_type) == 0) {
1573*7c478bd9Sstevel@tonic-gate 		new_val->val_size = strlen((char *)val) + 1;
1574*7c478bd9Sstevel@tonic-gate 		new_val->val.string = (char *)val;
1575*7c478bd9Sstevel@tonic-gate 	} else {
1576*7c478bd9Sstevel@tonic-gate 		new_val->val_size = sizeof (int);
1577*7c478bd9Sstevel@tonic-gate 		new_val->val.integer = (int)(uintptr_t)val;
1578*7c478bd9Sstevel@tonic-gate 	}
1579*7c478bd9Sstevel@tonic-gate 
1580*7c478bd9Sstevel@tonic-gate 	if (listp) {
1581*7c478bd9Sstevel@tonic-gate 		while (listp->val_next) {
1582*7c478bd9Sstevel@tonic-gate 			listp = listp->val_next;
1583*7c478bd9Sstevel@tonic-gate 		}
1584*7c478bd9Sstevel@tonic-gate 		listp->val_next = new_val;
1585*7c478bd9Sstevel@tonic-gate 	} else {
1586*7c478bd9Sstevel@tonic-gate 		*val_listp = new_val;
1587*7c478bd9Sstevel@tonic-gate 	}
1588*7c478bd9Sstevel@tonic-gate }
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate /*
1591*7c478bd9Sstevel@tonic-gate  * make sure there are no reserved IEEE 1275 characters (except
1592*7c478bd9Sstevel@tonic-gate  * for uppercase characters).
1593*7c478bd9Sstevel@tonic-gate  */
1594*7c478bd9Sstevel@tonic-gate static int
1595*7c478bd9Sstevel@tonic-gate valid_prop_name(char *name)
1596*7c478bd9Sstevel@tonic-gate {
1597*7c478bd9Sstevel@tonic-gate 	int i;
1598*7c478bd9Sstevel@tonic-gate 	int len = strlen(name);
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
1601*7c478bd9Sstevel@tonic-gate 		if (name[i] < 0x21 ||
1602*7c478bd9Sstevel@tonic-gate 			name[i] == '/' ||
1603*7c478bd9Sstevel@tonic-gate 			name[i] == '\\' ||
1604*7c478bd9Sstevel@tonic-gate 			name[i] == ':' ||
1605*7c478bd9Sstevel@tonic-gate 			name[i] == '[' ||
1606*7c478bd9Sstevel@tonic-gate 			name[i] == ']' ||
1607*7c478bd9Sstevel@tonic-gate 			name[i] == '@')
1608*7c478bd9Sstevel@tonic-gate 				return (0);
1609*7c478bd9Sstevel@tonic-gate 	}
1610*7c478bd9Sstevel@tonic-gate 	return (1);
1611*7c478bd9Sstevel@tonic-gate }
1612*7c478bd9Sstevel@tonic-gate 
1613*7c478bd9Sstevel@tonic-gate static void
1614*7c478bd9Sstevel@tonic-gate make_prop(struct _buf *file, dev_info_t *devi, char *name, struct val_list *val)
1615*7c478bd9Sstevel@tonic-gate {
1616*7c478bd9Sstevel@tonic-gate 	int propcnt = 0, val_type;
1617*7c478bd9Sstevel@tonic-gate 	struct val_list *vl, *tvl;
1618*7c478bd9Sstevel@tonic-gate 	caddr_t valbuf = NULL;
1619*7c478bd9Sstevel@tonic-gate 	char **valsp;
1620*7c478bd9Sstevel@tonic-gate 	int *valip;
1621*7c478bd9Sstevel@tonic-gate 
1622*7c478bd9Sstevel@tonic-gate 	if (name == NULL)
1623*7c478bd9Sstevel@tonic-gate 		return;
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1626*7c478bd9Sstevel@tonic-gate 	parse_debug(NULL, "%s", name);
1627*7c478bd9Sstevel@tonic-gate #endif
1628*7c478bd9Sstevel@tonic-gate 	if (!valid_prop_name(name)) {
1629*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "invalid property name '%s'", name);
1630*7c478bd9Sstevel@tonic-gate 		kmem_free(name, strlen(name) + 1);
1631*7c478bd9Sstevel@tonic-gate 		return;
1632*7c478bd9Sstevel@tonic-gate 	}
1633*7c478bd9Sstevel@tonic-gate 	if (val) {
1634*7c478bd9Sstevel@tonic-gate 		for (vl = val, val_type = vl->val_type; vl; vl = vl->val_next) {
1635*7c478bd9Sstevel@tonic-gate 			if (val_type != vl->val_type) {
1636*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "Mixed types in value list");
1637*7c478bd9Sstevel@tonic-gate 				return;
1638*7c478bd9Sstevel@tonic-gate 			}
1639*7c478bd9Sstevel@tonic-gate 			propcnt++;
1640*7c478bd9Sstevel@tonic-gate 		}
1641*7c478bd9Sstevel@tonic-gate 
1642*7c478bd9Sstevel@tonic-gate 		vl = val;
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 		if (val_type == 1) {
1645*7c478bd9Sstevel@tonic-gate 			valip = (int *)kmem_alloc(
1646*7c478bd9Sstevel@tonic-gate 			    (propcnt * sizeof (int)), KM_SLEEP);
1647*7c478bd9Sstevel@tonic-gate 			valbuf = (caddr_t)valip;
1648*7c478bd9Sstevel@tonic-gate 			while (vl) {
1649*7c478bd9Sstevel@tonic-gate 				tvl = vl;
1650*7c478bd9Sstevel@tonic-gate 				vl = vl->val_next;
1651*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1652*7c478bd9Sstevel@tonic-gate 				parse_debug(NULL, " %x",  tvl->val.integer);
1653*7c478bd9Sstevel@tonic-gate #endif
1654*7c478bd9Sstevel@tonic-gate 				*valip = tvl->val.integer;
1655*7c478bd9Sstevel@tonic-gate 				valip++;
1656*7c478bd9Sstevel@tonic-gate 				kmem_free(tvl, sizeof (struct val_list));
1657*7c478bd9Sstevel@tonic-gate 			}
1658*7c478bd9Sstevel@tonic-gate 			/* restore valip */
1659*7c478bd9Sstevel@tonic-gate 			valip = (int *)valbuf;
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 			/* create the property */
1662*7c478bd9Sstevel@tonic-gate 			if (e_ddi_prop_update_int_array(DDI_DEV_T_NONE, devi,
1663*7c478bd9Sstevel@tonic-gate 			    name, valip, propcnt) != DDI_PROP_SUCCESS) {
1664*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
1665*7c478bd9Sstevel@tonic-gate 				    "cannot create property %s", name);
1666*7c478bd9Sstevel@tonic-gate 			}
1667*7c478bd9Sstevel@tonic-gate 			/* cleanup */
1668*7c478bd9Sstevel@tonic-gate 			kmem_free(valip, (propcnt * sizeof (int)));
1669*7c478bd9Sstevel@tonic-gate 		} else if (val_type == 0) {
1670*7c478bd9Sstevel@tonic-gate 			valsp = (char **)kmem_alloc(
1671*7c478bd9Sstevel@tonic-gate 			    ((propcnt + 1) * sizeof (char *)), KM_SLEEP);
1672*7c478bd9Sstevel@tonic-gate 			valbuf = (caddr_t)valsp;
1673*7c478bd9Sstevel@tonic-gate 			while (vl) {
1674*7c478bd9Sstevel@tonic-gate 				tvl = vl;
1675*7c478bd9Sstevel@tonic-gate 				vl = vl->val_next;
1676*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1677*7c478bd9Sstevel@tonic-gate 				parse_debug(NULL, " %s", tvl->val.string);
1678*7c478bd9Sstevel@tonic-gate #endif
1679*7c478bd9Sstevel@tonic-gate 				*valsp = tvl->val.string;
1680*7c478bd9Sstevel@tonic-gate 				valsp++;
1681*7c478bd9Sstevel@tonic-gate 			}
1682*7c478bd9Sstevel@tonic-gate 			/* terminate array with NULL */
1683*7c478bd9Sstevel@tonic-gate 			*valsp = NULL;
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate 			/* restore valsp */
1686*7c478bd9Sstevel@tonic-gate 			valsp = (char **)valbuf;
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 			/* create the property */
1689*7c478bd9Sstevel@tonic-gate 			if (e_ddi_prop_update_string_array(DDI_DEV_T_NONE,
1690*7c478bd9Sstevel@tonic-gate 			    devi, name, valsp, propcnt)
1691*7c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
1692*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
1693*7c478bd9Sstevel@tonic-gate 				    "cannot create property %s", name);
1694*7c478bd9Sstevel@tonic-gate 			}
1695*7c478bd9Sstevel@tonic-gate 			/* Clean up */
1696*7c478bd9Sstevel@tonic-gate 			vl = val;
1697*7c478bd9Sstevel@tonic-gate 			while (vl) {
1698*7c478bd9Sstevel@tonic-gate 				tvl = vl;
1699*7c478bd9Sstevel@tonic-gate 				vl = vl->val_next;
1700*7c478bd9Sstevel@tonic-gate 				kmem_free(tvl->val.string, tvl->val_size);
1701*7c478bd9Sstevel@tonic-gate 				kmem_free(tvl, sizeof (struct val_list));
1702*7c478bd9Sstevel@tonic-gate 			}
1703*7c478bd9Sstevel@tonic-gate 			kmem_free(valsp, ((propcnt + 1) * sizeof (char *)));
1704*7c478bd9Sstevel@tonic-gate 		} else {
1705*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Invalid property type");
1706*7c478bd9Sstevel@tonic-gate 			return;
1707*7c478bd9Sstevel@tonic-gate 		}
1708*7c478bd9Sstevel@tonic-gate 	} else {
1709*7c478bd9Sstevel@tonic-gate 		/*
1710*7c478bd9Sstevel@tonic-gate 		 * No value was passed in with property so we will assume
1711*7c478bd9Sstevel@tonic-gate 		 * it is a "boolean" property and create an integer
1712*7c478bd9Sstevel@tonic-gate 		 * property with 0 value.
1713*7c478bd9Sstevel@tonic-gate 		 */
1714*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1715*7c478bd9Sstevel@tonic-gate 		parse_debug(NULL, "\n");
1716*7c478bd9Sstevel@tonic-gate #endif
1717*7c478bd9Sstevel@tonic-gate 		if (e_ddi_prop_update_int(DDI_DEV_T_NONE, devi, name, 0)
1718*7c478bd9Sstevel@tonic-gate 		    != DDI_PROP_SUCCESS) {
1719*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file,
1720*7c478bd9Sstevel@tonic-gate 			    "cannot create property %s", name);
1721*7c478bd9Sstevel@tonic-gate 		}
1722*7c478bd9Sstevel@tonic-gate 	}
1723*7c478bd9Sstevel@tonic-gate 	kmem_free(name, strlen(name) + 1);
1724*7c478bd9Sstevel@tonic-gate }
1725*7c478bd9Sstevel@tonic-gate 
1726*7c478bd9Sstevel@tonic-gate static char omit_err[] = "(the ';' may have been omitted on previous spec!)";
1727*7c478bd9Sstevel@tonic-gate static char prnt_err[] = "'parent' property already specified";
1728*7c478bd9Sstevel@tonic-gate static char nm_err[] = "'name' property already specified";
1729*7c478bd9Sstevel@tonic-gate static char class_err[] = "'class' property already specified";
1730*7c478bd9Sstevel@tonic-gate 
1731*7c478bd9Sstevel@tonic-gate typedef enum {
1732*7c478bd9Sstevel@tonic-gate 	hwc_begin, parent, drvname, drvclass, prop,
1733*7c478bd9Sstevel@tonic-gate 	parent_equals, name_equals, drvclass_equals,
1734*7c478bd9Sstevel@tonic-gate 	parent_equals_string, name_equals_string,
1735*7c478bd9Sstevel@tonic-gate 	drvclass_equals_string,
1736*7c478bd9Sstevel@tonic-gate 	prop_equals, prop_equals_string, prop_equals_integer,
1737*7c478bd9Sstevel@tonic-gate 	prop_equals_string_comma, prop_equals_integer_comma
1738*7c478bd9Sstevel@tonic-gate } hwc_state_t;
1739*7c478bd9Sstevel@tonic-gate 
1740*7c478bd9Sstevel@tonic-gate static struct hwc_spec *
1741*7c478bd9Sstevel@tonic-gate get_hwc_spec(struct _buf *file, char *tokbuf, size_t linesize)
1742*7c478bd9Sstevel@tonic-gate {
1743*7c478bd9Sstevel@tonic-gate 	char *prop_name, *string, *class_string;
1744*7c478bd9Sstevel@tonic-gate 	token_t token;
1745*7c478bd9Sstevel@tonic-gate 	struct hwc_spec *hwcp;
1746*7c478bd9Sstevel@tonic-gate 	struct dev_info *devi;
1747*7c478bd9Sstevel@tonic-gate 	struct val_list *val_list;
1748*7c478bd9Sstevel@tonic-gate 	hwc_state_t state;
1749*7c478bd9Sstevel@tonic-gate 	u_longlong_t ival;
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate 	hwcp = kmem_zalloc(sizeof (*hwcp), KM_SLEEP);
1752*7c478bd9Sstevel@tonic-gate 	devi = kmem_zalloc(sizeof (*devi), KM_SLEEP);
1753*7c478bd9Sstevel@tonic-gate 
1754*7c478bd9Sstevel@tonic-gate 	state = hwc_begin;
1755*7c478bd9Sstevel@tonic-gate 	token = NAME;
1756*7c478bd9Sstevel@tonic-gate 	prop_name = NULL;
1757*7c478bd9Sstevel@tonic-gate 	val_list = NULL;
1758*7c478bd9Sstevel@tonic-gate 	string = NULL;
1759*7c478bd9Sstevel@tonic-gate 	do {
1760*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1761*7c478bd9Sstevel@tonic-gate 		parse_debug(NULL, "state 0x%x\n", state);
1762*7c478bd9Sstevel@tonic-gate #endif
1763*7c478bd9Sstevel@tonic-gate 		switch (token) {
1764*7c478bd9Sstevel@tonic-gate 		case NAME:
1765*7c478bd9Sstevel@tonic-gate 			switch (state) {
1766*7c478bd9Sstevel@tonic-gate 			case prop:
1767*7c478bd9Sstevel@tonic-gate 			case prop_equals_string:
1768*7c478bd9Sstevel@tonic-gate 			case prop_equals_integer:
1769*7c478bd9Sstevel@tonic-gate 				make_prop(file, (dev_info_t *)devi,
1770*7c478bd9Sstevel@tonic-gate 				    prop_name, val_list);
1771*7c478bd9Sstevel@tonic-gate 				prop_name = NULL;
1772*7c478bd9Sstevel@tonic-gate 				val_list = NULL;
1773*7c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
1774*7c478bd9Sstevel@tonic-gate 			case hwc_begin:
1775*7c478bd9Sstevel@tonic-gate 				if (strcmp(tokbuf, "PARENT") == 0 ||
1776*7c478bd9Sstevel@tonic-gate 				    strcmp(tokbuf, "parent") == 0) {
1777*7c478bd9Sstevel@tonic-gate 					state = parent;
1778*7c478bd9Sstevel@tonic-gate 				} else if (strcmp(tokbuf, "NAME") == 0 ||
1779*7c478bd9Sstevel@tonic-gate 				    strcmp(tokbuf, "name") == 0) {
1780*7c478bd9Sstevel@tonic-gate 					state = drvname;
1781*7c478bd9Sstevel@tonic-gate 				} else if (strcmp(tokbuf, "CLASS") == 0 ||
1782*7c478bd9Sstevel@tonic-gate 				    strcmp(tokbuf, "class") == 0) {
1783*7c478bd9Sstevel@tonic-gate 					state = drvclass;
1784*7c478bd9Sstevel@tonic-gate 					prop_name = kmem_alloc(strlen(tokbuf) +
1785*7c478bd9Sstevel@tonic-gate 						1, KM_SLEEP);
1786*7c478bd9Sstevel@tonic-gate 					(void) strcpy(prop_name, tokbuf);
1787*7c478bd9Sstevel@tonic-gate 				} else {
1788*7c478bd9Sstevel@tonic-gate 					state = prop;
1789*7c478bd9Sstevel@tonic-gate 					prop_name = kmem_alloc(strlen(tokbuf) +
1790*7c478bd9Sstevel@tonic-gate 						1, KM_SLEEP);
1791*7c478bd9Sstevel@tonic-gate 					(void) strcpy(prop_name, tokbuf);
1792*7c478bd9Sstevel@tonic-gate 				}
1793*7c478bd9Sstevel@tonic-gate 				break;
1794*7c478bd9Sstevel@tonic-gate 			default:
1795*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1796*7c478bd9Sstevel@tonic-gate 			}
1797*7c478bd9Sstevel@tonic-gate 			break;
1798*7c478bd9Sstevel@tonic-gate 		case EQUALS:
1799*7c478bd9Sstevel@tonic-gate 			switch (state) {
1800*7c478bd9Sstevel@tonic-gate 			case drvname:
1801*7c478bd9Sstevel@tonic-gate 				state = name_equals;
1802*7c478bd9Sstevel@tonic-gate 				break;
1803*7c478bd9Sstevel@tonic-gate 			case parent:
1804*7c478bd9Sstevel@tonic-gate 				state = parent_equals;
1805*7c478bd9Sstevel@tonic-gate 				break;
1806*7c478bd9Sstevel@tonic-gate 			case drvclass:
1807*7c478bd9Sstevel@tonic-gate 				state = drvclass_equals;
1808*7c478bd9Sstevel@tonic-gate 				break;
1809*7c478bd9Sstevel@tonic-gate 			case prop:
1810*7c478bd9Sstevel@tonic-gate 				state = prop_equals;
1811*7c478bd9Sstevel@tonic-gate 				break;
1812*7c478bd9Sstevel@tonic-gate 			default:
1813*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1814*7c478bd9Sstevel@tonic-gate 			}
1815*7c478bd9Sstevel@tonic-gate 			break;
1816*7c478bd9Sstevel@tonic-gate 		case STRING:
1817*7c478bd9Sstevel@tonic-gate 			string = kmem_alloc(strlen(tokbuf) + 1, KM_SLEEP);
1818*7c478bd9Sstevel@tonic-gate 			(void) strcpy(string, tokbuf);
1819*7c478bd9Sstevel@tonic-gate 			switch (state) {
1820*7c478bd9Sstevel@tonic-gate 			case name_equals:
1821*7c478bd9Sstevel@tonic-gate 				if (ddi_get_name((dev_info_t *)devi)) {
1822*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, "%s %s",
1823*7c478bd9Sstevel@tonic-gate 						nm_err, omit_err);
1824*7c478bd9Sstevel@tonic-gate 					goto bad;
1825*7c478bd9Sstevel@tonic-gate 				}
1826*7c478bd9Sstevel@tonic-gate 				devi->devi_name = string;
1827*7c478bd9Sstevel@tonic-gate 				string = NULL;
1828*7c478bd9Sstevel@tonic-gate 				state = hwc_begin;
1829*7c478bd9Sstevel@tonic-gate 				break;
1830*7c478bd9Sstevel@tonic-gate 			case parent_equals:
1831*7c478bd9Sstevel@tonic-gate 				if (hwcp->hwc_parent_name) {
1832*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, "%s %s",
1833*7c478bd9Sstevel@tonic-gate 						prnt_err, omit_err);
1834*7c478bd9Sstevel@tonic-gate 					goto bad;
1835*7c478bd9Sstevel@tonic-gate 				}
1836*7c478bd9Sstevel@tonic-gate 				hwcp->hwc_parent_name = string;
1837*7c478bd9Sstevel@tonic-gate 				string = NULL;
1838*7c478bd9Sstevel@tonic-gate 				state = hwc_begin;
1839*7c478bd9Sstevel@tonic-gate 				break;
1840*7c478bd9Sstevel@tonic-gate 			case drvclass_equals:
1841*7c478bd9Sstevel@tonic-gate 				if (hwcp->hwc_class_name) {
1842*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, class_err);
1843*7c478bd9Sstevel@tonic-gate 					goto bad;
1844*7c478bd9Sstevel@tonic-gate 				}
1845*7c478bd9Sstevel@tonic-gate 				class_string = kmem_alloc(strlen(string) + 1,
1846*7c478bd9Sstevel@tonic-gate 					KM_SLEEP);
1847*7c478bd9Sstevel@tonic-gate 				(void) strcpy(class_string, string);
1848*7c478bd9Sstevel@tonic-gate 				hwcp->hwc_class_name = class_string;
1849*7c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
1850*7c478bd9Sstevel@tonic-gate 			case prop_equals:
1851*7c478bd9Sstevel@tonic-gate 			case prop_equals_string_comma:
1852*7c478bd9Sstevel@tonic-gate 				add_val(&val_list, 0, string);
1853*7c478bd9Sstevel@tonic-gate 				string = NULL;
1854*7c478bd9Sstevel@tonic-gate 				state = prop_equals_string;
1855*7c478bd9Sstevel@tonic-gate 				break;
1856*7c478bd9Sstevel@tonic-gate 			default:
1857*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1858*7c478bd9Sstevel@tonic-gate 			}
1859*7c478bd9Sstevel@tonic-gate 			break;
1860*7c478bd9Sstevel@tonic-gate 		case HEXVAL:
1861*7c478bd9Sstevel@tonic-gate 		case DECVAL:
1862*7c478bd9Sstevel@tonic-gate 			switch (state) {
1863*7c478bd9Sstevel@tonic-gate 			case prop_equals:
1864*7c478bd9Sstevel@tonic-gate 			case prop_equals_integer_comma:
1865*7c478bd9Sstevel@tonic-gate 				(void) kobj_getvalue(tokbuf, &ival);
1866*7c478bd9Sstevel@tonic-gate 				add_val(&val_list, 1, (caddr_t)(uintptr_t)ival);
1867*7c478bd9Sstevel@tonic-gate 				state = prop_equals_integer;
1868*7c478bd9Sstevel@tonic-gate 				break;
1869*7c478bd9Sstevel@tonic-gate 			default:
1870*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1871*7c478bd9Sstevel@tonic-gate 			}
1872*7c478bd9Sstevel@tonic-gate 			break;
1873*7c478bd9Sstevel@tonic-gate 		case COMMA:
1874*7c478bd9Sstevel@tonic-gate 			switch (state) {
1875*7c478bd9Sstevel@tonic-gate 			case prop_equals_string:
1876*7c478bd9Sstevel@tonic-gate 				state = prop_equals_string_comma;
1877*7c478bd9Sstevel@tonic-gate 				break;
1878*7c478bd9Sstevel@tonic-gate 			case prop_equals_integer:
1879*7c478bd9Sstevel@tonic-gate 				state = prop_equals_integer_comma;
1880*7c478bd9Sstevel@tonic-gate 				break;
1881*7c478bd9Sstevel@tonic-gate 			default:
1882*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1883*7c478bd9Sstevel@tonic-gate 			}
1884*7c478bd9Sstevel@tonic-gate 			break;
1885*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
1886*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
1887*7c478bd9Sstevel@tonic-gate 			break;
1888*7c478bd9Sstevel@tonic-gate 		case POUND:
1889*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
1890*7c478bd9Sstevel@tonic-gate 			break;
1891*7c478bd9Sstevel@tonic-gate 		case EOF:
1892*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, "Unexpected EOF");
1893*7c478bd9Sstevel@tonic-gate 			goto bad;
1894*7c478bd9Sstevel@tonic-gate 		default:
1895*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, tok_err, tokbuf);
1896*7c478bd9Sstevel@tonic-gate 			goto bad;
1897*7c478bd9Sstevel@tonic-gate 		}
1898*7c478bd9Sstevel@tonic-gate 	} while ((token = kobj_lex(file, tokbuf, linesize)) != SEMICOLON);
1899*7c478bd9Sstevel@tonic-gate 
1900*7c478bd9Sstevel@tonic-gate 	switch (state) {
1901*7c478bd9Sstevel@tonic-gate 	case prop:
1902*7c478bd9Sstevel@tonic-gate 	case prop_equals_string:
1903*7c478bd9Sstevel@tonic-gate 	case prop_equals_integer:
1904*7c478bd9Sstevel@tonic-gate 		make_prop(file, (dev_info_t *)devi,
1905*7c478bd9Sstevel@tonic-gate 			prop_name, val_list);
1906*7c478bd9Sstevel@tonic-gate 		break;
1907*7c478bd9Sstevel@tonic-gate 
1908*7c478bd9Sstevel@tonic-gate 	case hwc_begin:
1909*7c478bd9Sstevel@tonic-gate 		break;
1910*7c478bd9Sstevel@tonic-gate 	default:
1911*7c478bd9Sstevel@tonic-gate 		kobj_file_err(CE_WARN, file, "Unexpected end of line");
1912*7c478bd9Sstevel@tonic-gate 		break;
1913*7c478bd9Sstevel@tonic-gate 	}
1914*7c478bd9Sstevel@tonic-gate 
1915*7c478bd9Sstevel@tonic-gate 	/* copy 2 relevant members of devi to hwcp */
1916*7c478bd9Sstevel@tonic-gate 	hwcp->hwc_devi_sys_prop_ptr = devi->devi_sys_prop_ptr;
1917*7c478bd9Sstevel@tonic-gate 	hwcp->hwc_devi_name = devi->devi_name;
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate 	kmem_free(devi, sizeof (struct dev_info));
1920*7c478bd9Sstevel@tonic-gate 
1921*7c478bd9Sstevel@tonic-gate 	return (hwcp);
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate bad:
1924*7c478bd9Sstevel@tonic-gate 	if (string) {
1925*7c478bd9Sstevel@tonic-gate 		kmem_free(string, strlen(string) + 1);
1926*7c478bd9Sstevel@tonic-gate 	}
1927*7c478bd9Sstevel@tonic-gate 	if (hwcp) {
1928*7c478bd9Sstevel@tonic-gate 		hwc_free(hwcp);
1929*7c478bd9Sstevel@tonic-gate 	}
1930*7c478bd9Sstevel@tonic-gate 	if (devi) {
1931*7c478bd9Sstevel@tonic-gate 		if (devi->devi_name)
1932*7c478bd9Sstevel@tonic-gate 			kmem_free(devi->devi_name,
1933*7c478bd9Sstevel@tonic-gate 			    strlen(devi->devi_name) + 1);
1934*7c478bd9Sstevel@tonic-gate 		kmem_free(devi, sizeof (struct dev_info));
1935*7c478bd9Sstevel@tonic-gate 	}
1936*7c478bd9Sstevel@tonic-gate 	return (NULL);
1937*7c478bd9Sstevel@tonic-gate }
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate /*
1940*7c478bd9Sstevel@tonic-gate  * This is the primary kernel interface to parse driver.conf files.
1941*7c478bd9Sstevel@tonic-gate  *
1942*7c478bd9Sstevel@tonic-gate  * Yet another bigstk thread handoff due to deep kernel stacks when booting
1943*7c478bd9Sstevel@tonic-gate  * cache-only-clients.
1944*7c478bd9Sstevel@tonic-gate  */
1945*7c478bd9Sstevel@tonic-gate int
1946*7c478bd9Sstevel@tonic-gate hwc_parse(char *fname, struct par_list **pl, ddi_prop_t **props)
1947*7c478bd9Sstevel@tonic-gate {
1948*7c478bd9Sstevel@tonic-gate 	int ret;
1949*7c478bd9Sstevel@tonic-gate 	struct hwc_parse_mt *pltp = hwc_parse_mtalloc(fname, pl, props);
1950*7c478bd9Sstevel@tonic-gate 
1951*7c478bd9Sstevel@tonic-gate 	if (curthread != &t0) {
1952*7c478bd9Sstevel@tonic-gate 		(void) thread_create(NULL, DEFAULTSTKSZ * 2,
1953*7c478bd9Sstevel@tonic-gate 		    hwc_parse_thread, pltp, 0, &p0, TS_RUN, maxclsyspri);
1954*7c478bd9Sstevel@tonic-gate 		sema_p(&pltp->sema);
1955*7c478bd9Sstevel@tonic-gate 	} else {
1956*7c478bd9Sstevel@tonic-gate 		pltp->rv = hwc_parse_now(fname, pl, props);
1957*7c478bd9Sstevel@tonic-gate 	}
1958*7c478bd9Sstevel@tonic-gate 	ret = pltp->rv;
1959*7c478bd9Sstevel@tonic-gate 	hwc_parse_mtfree(pltp);
1960*7c478bd9Sstevel@tonic-gate 	return (ret);
1961*7c478bd9Sstevel@tonic-gate }
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate /*
1964*7c478bd9Sstevel@tonic-gate  * Calls to hwc_parse() are handled off to this routine in a separate
1965*7c478bd9Sstevel@tonic-gate  * thread.
1966*7c478bd9Sstevel@tonic-gate  */
1967*7c478bd9Sstevel@tonic-gate static void
1968*7c478bd9Sstevel@tonic-gate hwc_parse_thread(struct hwc_parse_mt *pltp)
1969*7c478bd9Sstevel@tonic-gate {
1970*7c478bd9Sstevel@tonic-gate 	kmutex_t	cpr_lk;
1971*7c478bd9Sstevel@tonic-gate 	callb_cpr_t	cpr_i;
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 	mutex_init(&cpr_lk, NULL, MUTEX_DEFAULT, NULL);
1974*7c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cpr_i, &cpr_lk, callb_generic_cpr, "hwc_parse");
1975*7c478bd9Sstevel@tonic-gate 
1976*7c478bd9Sstevel@tonic-gate 	/*
1977*7c478bd9Sstevel@tonic-gate 	 * load and parse the .conf file
1978*7c478bd9Sstevel@tonic-gate 	 * return the hwc_spec list (if any) to the creator of this thread
1979*7c478bd9Sstevel@tonic-gate 	 */
1980*7c478bd9Sstevel@tonic-gate 	pltp->rv = hwc_parse_now(pltp->name, pltp->pl, pltp->props);
1981*7c478bd9Sstevel@tonic-gate 	sema_v(&pltp->sema);
1982*7c478bd9Sstevel@tonic-gate 	mutex_enter(&cpr_lk);
1983*7c478bd9Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cpr_i);
1984*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&cpr_lk);
1985*7c478bd9Sstevel@tonic-gate 	thread_exit();
1986*7c478bd9Sstevel@tonic-gate }
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate /*
1989*7c478bd9Sstevel@tonic-gate  * allocate and initialize a hwc_parse thread control structure
1990*7c478bd9Sstevel@tonic-gate  */
1991*7c478bd9Sstevel@tonic-gate static struct hwc_parse_mt *
1992*7c478bd9Sstevel@tonic-gate hwc_parse_mtalloc(char *name, struct par_list **pl, ddi_prop_t **props)
1993*7c478bd9Sstevel@tonic-gate {
1994*7c478bd9Sstevel@tonic-gate 	struct hwc_parse_mt *pltp = kmem_zalloc(sizeof (*pltp), KM_SLEEP);
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 	ASSERT(name != NULL);
1997*7c478bd9Sstevel@tonic-gate 
1998*7c478bd9Sstevel@tonic-gate 	pltp->name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
1999*7c478bd9Sstevel@tonic-gate 	bcopy(name, pltp->name, strlen(name) + 1);
2000*7c478bd9Sstevel@tonic-gate 	pltp->pl = pl;
2001*7c478bd9Sstevel@tonic-gate 	pltp->props = props;
2002*7c478bd9Sstevel@tonic-gate 
2003*7c478bd9Sstevel@tonic-gate 	sema_init(&pltp->sema, 0, NULL, SEMA_DEFAULT, NULL);
2004*7c478bd9Sstevel@tonic-gate 	return (pltp);
2005*7c478bd9Sstevel@tonic-gate }
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate /*
2008*7c478bd9Sstevel@tonic-gate  * free a hwc_parse thread control structure
2009*7c478bd9Sstevel@tonic-gate  */
2010*7c478bd9Sstevel@tonic-gate static void
2011*7c478bd9Sstevel@tonic-gate hwc_parse_mtfree(struct hwc_parse_mt *pltp)
2012*7c478bd9Sstevel@tonic-gate {
2013*7c478bd9Sstevel@tonic-gate 	sema_destroy(&pltp->sema);
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate 	kmem_free(pltp->name, strlen(pltp->name) + 1);
2016*7c478bd9Sstevel@tonic-gate 	kmem_free(pltp, sizeof (*pltp));
2017*7c478bd9Sstevel@tonic-gate }
2018*7c478bd9Sstevel@tonic-gate 
2019*7c478bd9Sstevel@tonic-gate /*
2020*7c478bd9Sstevel@tonic-gate  * hwc_parse -- parse an hwconf file.  Ignore error lines and parse
2021*7c478bd9Sstevel@tonic-gate  * as much as possible.
2022*7c478bd9Sstevel@tonic-gate  */
2023*7c478bd9Sstevel@tonic-gate static int
2024*7c478bd9Sstevel@tonic-gate hwc_parse_now(char *fname, struct par_list **pl, ddi_prop_t **props)
2025*7c478bd9Sstevel@tonic-gate {
2026*7c478bd9Sstevel@tonic-gate 	struct _buf *file;
2027*7c478bd9Sstevel@tonic-gate 	struct hwc_spec *hwcp;
2028*7c478bd9Sstevel@tonic-gate 	char *tokval;
2029*7c478bd9Sstevel@tonic-gate 	token_t token;
2030*7c478bd9Sstevel@tonic-gate 
2031*7c478bd9Sstevel@tonic-gate 	/*
2032*7c478bd9Sstevel@tonic-gate 	 * Don't use kobj_open_path's use_moddir_suffix option, we only
2033*7c478bd9Sstevel@tonic-gate 	 * expect to find conf files in the base module directory, not
2034*7c478bd9Sstevel@tonic-gate 	 * an ISA-specific subdirectory.
2035*7c478bd9Sstevel@tonic-gate 	 */
2036*7c478bd9Sstevel@tonic-gate 	if ((file = kobj_open_path(fname, 1, 0)) == (struct _buf *)-1) {
2037*7c478bd9Sstevel@tonic-gate 		if (moddebug & MODDEBUG_ERRMSG)
2038*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Cannot open %s", fname);
2039*7c478bd9Sstevel@tonic-gate 		return (-1);
2040*7c478bd9Sstevel@tonic-gate 	}
2041*7c478bd9Sstevel@tonic-gate 
2042*7c478bd9Sstevel@tonic-gate 	/*
2043*7c478bd9Sstevel@tonic-gate 	 * Initialize variables
2044*7c478bd9Sstevel@tonic-gate 	 */
2045*7c478bd9Sstevel@tonic-gate 	tokval = kmem_alloc(MAX_HWC_LINESIZE, KM_SLEEP);
2046*7c478bd9Sstevel@tonic-gate 
2047*7c478bd9Sstevel@tonic-gate 	while ((token = kobj_lex(file, tokval, MAX_HWC_LINESIZE)) != EOF) {
2048*7c478bd9Sstevel@tonic-gate 		switch (token) {
2049*7c478bd9Sstevel@tonic-gate 		case POUND:
2050*7c478bd9Sstevel@tonic-gate 			/*
2051*7c478bd9Sstevel@tonic-gate 			 * Skip comments.
2052*7c478bd9Sstevel@tonic-gate 			 */
2053*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
2054*7c478bd9Sstevel@tonic-gate 			break;
2055*7c478bd9Sstevel@tonic-gate 		case NAME:
2056*7c478bd9Sstevel@tonic-gate 			hwcp = get_hwc_spec(file, tokval, MAX_HWC_LINESIZE);
2057*7c478bd9Sstevel@tonic-gate 			if (hwcp == NULL)
2058*7c478bd9Sstevel@tonic-gate 				break;
2059*7c478bd9Sstevel@tonic-gate 			/*
2060*7c478bd9Sstevel@tonic-gate 			 * No devi_name indicates global property.
2061*7c478bd9Sstevel@tonic-gate 			 * Make sure parent and class not NULL.
2062*7c478bd9Sstevel@tonic-gate 			 */
2063*7c478bd9Sstevel@tonic-gate 			if (hwcp->hwc_devi_name == NULL) {
2064*7c478bd9Sstevel@tonic-gate 				if (hwcp->hwc_parent_name ||
2065*7c478bd9Sstevel@tonic-gate 				    hwcp->hwc_class_name) {
2066*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
2067*7c478bd9Sstevel@tonic-gate 					    "missing name attribute");
2068*7c478bd9Sstevel@tonic-gate 					hwc_free(hwcp);
2069*7c478bd9Sstevel@tonic-gate 					continue;
2070*7c478bd9Sstevel@tonic-gate 				}
2071*7c478bd9Sstevel@tonic-gate 				/* Add to global property list */
2072*7c478bd9Sstevel@tonic-gate 				add_props(hwcp, props);
2073*7c478bd9Sstevel@tonic-gate 				break;
2074*7c478bd9Sstevel@tonic-gate 			}
2075*7c478bd9Sstevel@tonic-gate 
2076*7c478bd9Sstevel@tonic-gate 			/*
2077*7c478bd9Sstevel@tonic-gate 			 * This is a node spec, either parent or class
2078*7c478bd9Sstevel@tonic-gate 			 * must be specified.
2079*7c478bd9Sstevel@tonic-gate 			 */
2080*7c478bd9Sstevel@tonic-gate 			if ((hwcp->hwc_parent_name == NULL) &&
2081*7c478bd9Sstevel@tonic-gate 			    (hwcp->hwc_class_name == NULL)) {
2082*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
2083*7c478bd9Sstevel@tonic-gate 				    "missing parent or class attribute");
2084*7c478bd9Sstevel@tonic-gate 				hwc_free(hwcp);
2085*7c478bd9Sstevel@tonic-gate 				continue;
2086*7c478bd9Sstevel@tonic-gate 			}
2087*7c478bd9Sstevel@tonic-gate 
2088*7c478bd9Sstevel@tonic-gate 			/* add to node spec list */
2089*7c478bd9Sstevel@tonic-gate 			add_spec(hwcp, pl);
2090*7c478bd9Sstevel@tonic-gate 			break;
2091*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
2092*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
2093*7c478bd9Sstevel@tonic-gate 			break;
2094*7c478bd9Sstevel@tonic-gate 		default:
2095*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, tok_err, tokval);
2096*7c478bd9Sstevel@tonic-gate 			break;
2097*7c478bd9Sstevel@tonic-gate 		}
2098*7c478bd9Sstevel@tonic-gate 	}
2099*7c478bd9Sstevel@tonic-gate 	/*
2100*7c478bd9Sstevel@tonic-gate 	 * XXX - Check for clean termination.
2101*7c478bd9Sstevel@tonic-gate 	 */
2102*7c478bd9Sstevel@tonic-gate 	kmem_free(tokval, MAX_HWC_LINESIZE);
2103*7c478bd9Sstevel@tonic-gate 	kobj_close_file(file);
2104*7c478bd9Sstevel@tonic-gate 	return (0);	/* always return success */
2105*7c478bd9Sstevel@tonic-gate }
2106*7c478bd9Sstevel@tonic-gate 
2107*7c478bd9Sstevel@tonic-gate void
2108*7c478bd9Sstevel@tonic-gate make_aliases(struct bind **bhash)
2109*7c478bd9Sstevel@tonic-gate {
2110*7c478bd9Sstevel@tonic-gate 	enum {
2111*7c478bd9Sstevel@tonic-gate 		AL_NEW, AL_DRVNAME, AL_DRVNAME_COMMA, AL_ALIAS, AL_ALIAS_COMMA
2112*7c478bd9Sstevel@tonic-gate 	} state;
2113*7c478bd9Sstevel@tonic-gate 
2114*7c478bd9Sstevel@tonic-gate 	struct _buf *file;
2115*7c478bd9Sstevel@tonic-gate 	char tokbuf[MAXNAMELEN];
2116*7c478bd9Sstevel@tonic-gate 	char drvbuf[MAXNAMELEN];
2117*7c478bd9Sstevel@tonic-gate 	token_t token;
2118*7c478bd9Sstevel@tonic-gate 	major_t major;
2119*7c478bd9Sstevel@tonic-gate 	int done = 0;
2120*7c478bd9Sstevel@tonic-gate 	static char dupwarn[] = "!Driver alias \"%s\" conflicts with "
2121*7c478bd9Sstevel@tonic-gate 	    "an existing driver name or alias.";
2122*7c478bd9Sstevel@tonic-gate 
2123*7c478bd9Sstevel@tonic-gate 	if ((file = kobj_open_file(dafile)) == (struct _buf *)-1)
2124*7c478bd9Sstevel@tonic-gate 		return;
2125*7c478bd9Sstevel@tonic-gate 
2126*7c478bd9Sstevel@tonic-gate 	state = AL_NEW;
2127*7c478bd9Sstevel@tonic-gate 	major = (major_t)-1;
2128*7c478bd9Sstevel@tonic-gate 	while (!done) {
2129*7c478bd9Sstevel@tonic-gate 		token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2130*7c478bd9Sstevel@tonic-gate 		switch (token) {
2131*7c478bd9Sstevel@tonic-gate 		case POUND:
2132*7c478bd9Sstevel@tonic-gate 			state = AL_NEW;
2133*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
2134*7c478bd9Sstevel@tonic-gate 			break;
2135*7c478bd9Sstevel@tonic-gate 		case NAME:
2136*7c478bd9Sstevel@tonic-gate 		case STRING:
2137*7c478bd9Sstevel@tonic-gate 			switch (state) {
2138*7c478bd9Sstevel@tonic-gate 			case AL_NEW:
2139*7c478bd9Sstevel@tonic-gate 				(void) strcpy(drvbuf, tokbuf);
2140*7c478bd9Sstevel@tonic-gate 				state = AL_DRVNAME;
2141*7c478bd9Sstevel@tonic-gate 				break;
2142*7c478bd9Sstevel@tonic-gate 			case AL_DRVNAME_COMMA:
2143*7c478bd9Sstevel@tonic-gate 				(void) strcat(drvbuf, tokbuf);
2144*7c478bd9Sstevel@tonic-gate 				state = AL_DRVNAME;
2145*7c478bd9Sstevel@tonic-gate 				break;
2146*7c478bd9Sstevel@tonic-gate 			case AL_ALIAS_COMMA:
2147*7c478bd9Sstevel@tonic-gate 				(void) strcat(drvbuf, tokbuf);
2148*7c478bd9Sstevel@tonic-gate 				state = AL_ALIAS;
2149*7c478bd9Sstevel@tonic-gate 				break;
2150*7c478bd9Sstevel@tonic-gate 			case AL_DRVNAME:
2151*7c478bd9Sstevel@tonic-gate 				major = mod_name_to_major(drvbuf);
2152*7c478bd9Sstevel@tonic-gate 				if (major == (major_t)-1) {
2153*7c478bd9Sstevel@tonic-gate 					kobj_find_eol(file);
2154*7c478bd9Sstevel@tonic-gate 					state = AL_NEW;
2155*7c478bd9Sstevel@tonic-gate 				} else {
2156*7c478bd9Sstevel@tonic-gate 					(void) strcpy(drvbuf, tokbuf);
2157*7c478bd9Sstevel@tonic-gate 					state = AL_ALIAS;
2158*7c478bd9Sstevel@tonic-gate 				}
2159*7c478bd9Sstevel@tonic-gate 				break;
2160*7c478bd9Sstevel@tonic-gate 			case AL_ALIAS:
2161*7c478bd9Sstevel@tonic-gate 				if (make_mbind(drvbuf, major, NULL, bhash)
2162*7c478bd9Sstevel@tonic-gate 				    != 0) {
2163*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN, dupwarn, drvbuf);
2164*7c478bd9Sstevel@tonic-gate 				}
2165*7c478bd9Sstevel@tonic-gate 				break;
2166*7c478bd9Sstevel@tonic-gate 			}
2167*7c478bd9Sstevel@tonic-gate 			break;
2168*7c478bd9Sstevel@tonic-gate 		case COMMA:
2169*7c478bd9Sstevel@tonic-gate 			(void) strcat(drvbuf, tokbuf);
2170*7c478bd9Sstevel@tonic-gate 			switch (state) {
2171*7c478bd9Sstevel@tonic-gate 			case AL_DRVNAME:
2172*7c478bd9Sstevel@tonic-gate 				state = AL_DRVNAME_COMMA;
2173*7c478bd9Sstevel@tonic-gate 				break;
2174*7c478bd9Sstevel@tonic-gate 			case AL_ALIAS:
2175*7c478bd9Sstevel@tonic-gate 				state = AL_ALIAS_COMMA;
2176*7c478bd9Sstevel@tonic-gate 				break;
2177*7c478bd9Sstevel@tonic-gate 			default:
2178*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2179*7c478bd9Sstevel@tonic-gate 			}
2180*7c478bd9Sstevel@tonic-gate 			break;
2181*7c478bd9Sstevel@tonic-gate 		case EOF:
2182*7c478bd9Sstevel@tonic-gate 			done = 1;
2183*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
2184*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
2185*7c478bd9Sstevel@tonic-gate 			if (state == AL_ALIAS) {
2186*7c478bd9Sstevel@tonic-gate 				if (make_mbind(drvbuf, major, NULL, bhash)
2187*7c478bd9Sstevel@tonic-gate 				    != 0) {
2188*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN, dupwarn, drvbuf);
2189*7c478bd9Sstevel@tonic-gate 				}
2190*7c478bd9Sstevel@tonic-gate 			} else if (state != AL_NEW) {
2191*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
2192*7c478bd9Sstevel@tonic-gate 				    "Missing alias for %s", drvbuf);
2193*7c478bd9Sstevel@tonic-gate 			}
2194*7c478bd9Sstevel@tonic-gate 
2195*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
2196*7c478bd9Sstevel@tonic-gate 			state = AL_NEW;
2197*7c478bd9Sstevel@tonic-gate 			major = (major_t)-1;
2198*7c478bd9Sstevel@tonic-gate 			break;
2199*7c478bd9Sstevel@tonic-gate 		default:
2200*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2201*7c478bd9Sstevel@tonic-gate 		}
2202*7c478bd9Sstevel@tonic-gate 	}
2203*7c478bd9Sstevel@tonic-gate 
2204*7c478bd9Sstevel@tonic-gate 	kobj_close_file(file);
2205*7c478bd9Sstevel@tonic-gate }
2206*7c478bd9Sstevel@tonic-gate 
2207*7c478bd9Sstevel@tonic-gate 
2208*7c478bd9Sstevel@tonic-gate /*
2209*7c478bd9Sstevel@tonic-gate  * It is called for parsing these files:
2210*7c478bd9Sstevel@tonic-gate  * - /etc/path_to_inst
2211*7c478bd9Sstevel@tonic-gate  * - /etc/name_to_major
2212*7c478bd9Sstevel@tonic-gate  * - /etc/name_to_sysnum
2213*7c478bd9Sstevel@tonic-gate  * A callback "int (*line_parser)(char *, int, char *, struct bind **)"
2214*7c478bd9Sstevel@tonic-gate  * is invoked for each line of the file.
2215*7c478bd9Sstevel@tonic-gate  * The callback can inhash the entry into a hashtable by supplying
2216*7c478bd9Sstevel@tonic-gate  * a pre-allocated hashtable in "struct bind **hashtab".
2217*7c478bd9Sstevel@tonic-gate  */
2218*7c478bd9Sstevel@tonic-gate int
2219*7c478bd9Sstevel@tonic-gate read_binding_file(char *bindfile, struct bind **hashtab,
2220*7c478bd9Sstevel@tonic-gate     int (*line_parser)(char *, int, char *, struct bind **))
2221*7c478bd9Sstevel@tonic-gate {
2222*7c478bd9Sstevel@tonic-gate 	enum {
2223*7c478bd9Sstevel@tonic-gate 		B_NEW, B_NAME, B_VAL, B_BIND_NAME
2224*7c478bd9Sstevel@tonic-gate 	} state;
2225*7c478bd9Sstevel@tonic-gate 	struct _buf *file;
2226*7c478bd9Sstevel@tonic-gate 	char tokbuf[MAXNAMELEN];
2227*7c478bd9Sstevel@tonic-gate 	token_t token;
2228*7c478bd9Sstevel@tonic-gate 	int maxnum = 0;
2229*7c478bd9Sstevel@tonic-gate 	char *bind_name = NULL, *name = NULL, *bn = NULL;
2230*7c478bd9Sstevel@tonic-gate 	u_longlong_t val;
2231*7c478bd9Sstevel@tonic-gate 	int done = 0;
2232*7c478bd9Sstevel@tonic-gate 
2233*7c478bd9Sstevel@tonic-gate 	static char num_err[] = "Missing number on preceding line?";
2234*7c478bd9Sstevel@tonic-gate 	static char dupwarn[] = "!The binding file entry \"%s %u\" conflicts "
2235*7c478bd9Sstevel@tonic-gate 	    "with a previous entry";
2236*7c478bd9Sstevel@tonic-gate 
2237*7c478bd9Sstevel@tonic-gate 	if (hashtab != NULL) {
2238*7c478bd9Sstevel@tonic-gate 		clear_binding_hash(hashtab);
2239*7c478bd9Sstevel@tonic-gate 	}
2240*7c478bd9Sstevel@tonic-gate 
2241*7c478bd9Sstevel@tonic-gate 	if ((file = kobj_open_file(bindfile)) == (struct _buf *)-1)
2242*7c478bd9Sstevel@tonic-gate 		panic("read_binding_file: %s file not found", bindfile);
2243*7c478bd9Sstevel@tonic-gate 
2244*7c478bd9Sstevel@tonic-gate 	state = B_NEW;
2245*7c478bd9Sstevel@tonic-gate 
2246*7c478bd9Sstevel@tonic-gate 	while (!done) {
2247*7c478bd9Sstevel@tonic-gate 		token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2248*7c478bd9Sstevel@tonic-gate 
2249*7c478bd9Sstevel@tonic-gate 		switch (token) {
2250*7c478bd9Sstevel@tonic-gate 		case POUND:
2251*7c478bd9Sstevel@tonic-gate 			state = B_NEW;
2252*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
2253*7c478bd9Sstevel@tonic-gate 			break;
2254*7c478bd9Sstevel@tonic-gate 		case NAME:
2255*7c478bd9Sstevel@tonic-gate 		case STRING:
2256*7c478bd9Sstevel@tonic-gate 			switch (state) {
2257*7c478bd9Sstevel@tonic-gate 			case B_NEW:
2258*7c478bd9Sstevel@tonic-gate 				/*
2259*7c478bd9Sstevel@tonic-gate 				 * This case is for the first name and
2260*7c478bd9Sstevel@tonic-gate 				 * possibly only name in an entry.
2261*7c478bd9Sstevel@tonic-gate 				 */
2262*7c478bd9Sstevel@tonic-gate 				ASSERT(name == NULL);
2263*7c478bd9Sstevel@tonic-gate 				name = kmem_alloc(strlen(tokbuf) + 1, KM_SLEEP);
2264*7c478bd9Sstevel@tonic-gate 				(void) strcpy(name, tokbuf);
2265*7c478bd9Sstevel@tonic-gate 				state = B_NAME;
2266*7c478bd9Sstevel@tonic-gate 				break;
2267*7c478bd9Sstevel@tonic-gate 			case B_VAL:
2268*7c478bd9Sstevel@tonic-gate 				/*
2269*7c478bd9Sstevel@tonic-gate 				 * This case is for a second name, which
2270*7c478bd9Sstevel@tonic-gate 				 * would be the binding name if the first
2271*7c478bd9Sstevel@tonic-gate 				 * name was actually a generic name.
2272*7c478bd9Sstevel@tonic-gate 				 */
2273*7c478bd9Sstevel@tonic-gate 				ASSERT(bind_name == NULL);
2274*7c478bd9Sstevel@tonic-gate 				bind_name = kmem_alloc(strlen(tokbuf) + 1,
2275*7c478bd9Sstevel@tonic-gate 				    KM_SLEEP);
2276*7c478bd9Sstevel@tonic-gate 				(void) strcpy(bind_name, tokbuf);
2277*7c478bd9Sstevel@tonic-gate 				state = B_BIND_NAME;
2278*7c478bd9Sstevel@tonic-gate 				break;
2279*7c478bd9Sstevel@tonic-gate 			default:
2280*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, num_err);
2281*7c478bd9Sstevel@tonic-gate 			}
2282*7c478bd9Sstevel@tonic-gate 			break;
2283*7c478bd9Sstevel@tonic-gate 		case HEXVAL:
2284*7c478bd9Sstevel@tonic-gate 		case DECVAL:
2285*7c478bd9Sstevel@tonic-gate 			if (state != B_NAME) {
2286*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, "Missing name?");
2287*7c478bd9Sstevel@tonic-gate 				state = B_NEW;
2288*7c478bd9Sstevel@tonic-gate 				continue;
2289*7c478bd9Sstevel@tonic-gate 			}
2290*7c478bd9Sstevel@tonic-gate 			(void) kobj_getvalue(tokbuf, &val);
2291*7c478bd9Sstevel@tonic-gate 			if (val > (u_longlong_t)INT_MAX) {
2292*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
2293*7c478bd9Sstevel@tonic-gate 				    "value %llu too large", val);
2294*7c478bd9Sstevel@tonic-gate 				state = B_NEW;
2295*7c478bd9Sstevel@tonic-gate 				continue;
2296*7c478bd9Sstevel@tonic-gate 			}
2297*7c478bd9Sstevel@tonic-gate 			state = B_VAL;
2298*7c478bd9Sstevel@tonic-gate 			break;
2299*7c478bd9Sstevel@tonic-gate 		case EOF:
2300*7c478bd9Sstevel@tonic-gate 			done = 1;
2301*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
2302*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
2303*7c478bd9Sstevel@tonic-gate 			if ((state == B_BIND_NAME) || (state == B_VAL)) {
2304*7c478bd9Sstevel@tonic-gate 				if (state == B_BIND_NAME)
2305*7c478bd9Sstevel@tonic-gate 					bn = bind_name;
2306*7c478bd9Sstevel@tonic-gate 				else
2307*7c478bd9Sstevel@tonic-gate 					bn = NULL;
2308*7c478bd9Sstevel@tonic-gate 
2309*7c478bd9Sstevel@tonic-gate 				if (line_parser != NULL) {
2310*7c478bd9Sstevel@tonic-gate 					if ((*line_parser)(name, (int)val, bn,
2311*7c478bd9Sstevel@tonic-gate 					    hashtab) == 0)
2312*7c478bd9Sstevel@tonic-gate 						maxnum = MAX((int)val, maxnum);
2313*7c478bd9Sstevel@tonic-gate 					else
2314*7c478bd9Sstevel@tonic-gate 						kobj_file_err(CE_WARN, file,
2315*7c478bd9Sstevel@tonic-gate 						    dupwarn, name, (uint_t)val);
2316*7c478bd9Sstevel@tonic-gate 				}
2317*7c478bd9Sstevel@tonic-gate 			} else if (state != B_NEW)
2318*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, "Syntax error?");
2319*7c478bd9Sstevel@tonic-gate 
2320*7c478bd9Sstevel@tonic-gate 			if (name) {
2321*7c478bd9Sstevel@tonic-gate 				kmem_free(name, strlen(name) + 1);
2322*7c478bd9Sstevel@tonic-gate 				name = NULL;
2323*7c478bd9Sstevel@tonic-gate 			}
2324*7c478bd9Sstevel@tonic-gate 			if (bind_name) {
2325*7c478bd9Sstevel@tonic-gate 				kmem_free(bind_name, strlen(bind_name) + 1);
2326*7c478bd9Sstevel@tonic-gate 				bind_name = NULL;
2327*7c478bd9Sstevel@tonic-gate 			}
2328*7c478bd9Sstevel@tonic-gate 			state = B_NEW;
2329*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
2330*7c478bd9Sstevel@tonic-gate 			break;
2331*7c478bd9Sstevel@tonic-gate 		default:
2332*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, "Missing name/number?");
2333*7c478bd9Sstevel@tonic-gate 			break;
2334*7c478bd9Sstevel@tonic-gate 		}
2335*7c478bd9Sstevel@tonic-gate 	}
2336*7c478bd9Sstevel@tonic-gate 
2337*7c478bd9Sstevel@tonic-gate 	ASSERT(name == NULL);		/* any leaks? */
2338*7c478bd9Sstevel@tonic-gate 	ASSERT(bind_name == NULL);
2339*7c478bd9Sstevel@tonic-gate 
2340*7c478bd9Sstevel@tonic-gate 	kobj_close_file(file);
2341*7c478bd9Sstevel@tonic-gate 	return (maxnum);
2342*7c478bd9Sstevel@tonic-gate }
2343*7c478bd9Sstevel@tonic-gate 
2344*7c478bd9Sstevel@tonic-gate /*
2345*7c478bd9Sstevel@tonic-gate  * read_dacf_binding_file()
2346*7c478bd9Sstevel@tonic-gate  * 	Read the /etc/dacf.conf file and build the dacf_rule_t database from it.
2347*7c478bd9Sstevel@tonic-gate  *
2348*7c478bd9Sstevel@tonic-gate  * The syntax of a line in the dacf.conf file is:
2349*7c478bd9Sstevel@tonic-gate  *   dev-spec 	[module:]op-set	operation options 	[config-args];
2350*7c478bd9Sstevel@tonic-gate  *
2351*7c478bd9Sstevel@tonic-gate  * Where:
2352*7c478bd9Sstevel@tonic-gate  *   	1. dev-spec is of the format: name="data"
2353*7c478bd9Sstevel@tonic-gate  *   	2. operation is the operation that this rule matches. (i.e. pre-detach)
2354*7c478bd9Sstevel@tonic-gate  *   	3. options is a comma delimited list of options (i.e. debug,foobar)
2355*7c478bd9Sstevel@tonic-gate  *   	4. config-data is a whitespace delimited list of the format: name="data"
2356*7c478bd9Sstevel@tonic-gate  */
2357*7c478bd9Sstevel@tonic-gate int
2358*7c478bd9Sstevel@tonic-gate read_dacf_binding_file(char *filename)
2359*7c478bd9Sstevel@tonic-gate {
2360*7c478bd9Sstevel@tonic-gate 	enum {
2361*7c478bd9Sstevel@tonic-gate 		DACF_BEGIN,
2362*7c478bd9Sstevel@tonic-gate 		/* minor_nodetype="ddi_mouse:serial" */
2363*7c478bd9Sstevel@tonic-gate 		DACF_NT_SPEC, DACF_NT_EQUALS, DACF_NT_DATA,
2364*7c478bd9Sstevel@tonic-gate 		/* consconfig:mouseconfig */
2365*7c478bd9Sstevel@tonic-gate 		DACF_MN_MODNAME, DACF_MN_COLON, DACF_MN_OPSET,
2366*7c478bd9Sstevel@tonic-gate 		/* op */
2367*7c478bd9Sstevel@tonic-gate 		DACF_OP_NAME,
2368*7c478bd9Sstevel@tonic-gate 		/* [ option1, option2, option3... | - ] */
2369*7c478bd9Sstevel@tonic-gate 		DACF_OPT_OPTION, DACF_OPT_COMMA, DACF_OPT_END,
2370*7c478bd9Sstevel@tonic-gate 		/* argname1="argval1" argname2="argval2" ... */
2371*7c478bd9Sstevel@tonic-gate 		DACF_OPARG_SPEC, DACF_OPARG_EQUALS, DACF_OPARG_DATA,
2372*7c478bd9Sstevel@tonic-gate 		DACF_ERR, DACF_ERR_NEWLINE, DACF_COMMENT
2373*7c478bd9Sstevel@tonic-gate 	} state = DACF_BEGIN;
2374*7c478bd9Sstevel@tonic-gate 
2375*7c478bd9Sstevel@tonic-gate 	struct _buf *file;
2376*7c478bd9Sstevel@tonic-gate 	char *fname;
2377*7c478bd9Sstevel@tonic-gate 	token_t token;
2378*7c478bd9Sstevel@tonic-gate 
2379*7c478bd9Sstevel@tonic-gate 	char tokbuf[MAXNAMELEN];
2380*7c478bd9Sstevel@tonic-gate 	char mn_modname_buf[MAXNAMELEN], *mn_modnamep = NULL;
2381*7c478bd9Sstevel@tonic-gate 	char mn_opset_buf[MAXNAMELEN], *mn_opsetp = NULL;
2382*7c478bd9Sstevel@tonic-gate 	char nt_data_buf[MAXNAMELEN], *nt_datap = NULL;
2383*7c478bd9Sstevel@tonic-gate 	char arg_spec_buf[MAXNAMELEN];
2384*7c478bd9Sstevel@tonic-gate 
2385*7c478bd9Sstevel@tonic-gate 	uint_t opts = 0;
2386*7c478bd9Sstevel@tonic-gate 	dacf_devspec_t nt_spec_type = DACF_DS_ERROR;
2387*7c478bd9Sstevel@tonic-gate 
2388*7c478bd9Sstevel@tonic-gate 	dacf_arg_t *arg_list = NULL;
2389*7c478bd9Sstevel@tonic-gate 	dacf_opid_t opid = DACF_OPID_ERROR;
2390*7c478bd9Sstevel@tonic-gate 	int done = 0;
2391*7c478bd9Sstevel@tonic-gate 
2392*7c478bd9Sstevel@tonic-gate 	static char w_syntax[] = "'%s' unexpected";
2393*7c478bd9Sstevel@tonic-gate 	static char w_equals[] = "'=' is illegal in the current context";
2394*7c478bd9Sstevel@tonic-gate 	static char w_baddevspec[] = "device specification '%s' unrecognized";
2395*7c478bd9Sstevel@tonic-gate 	static char w_badop[] = "operation '%s' unrecognized";
2396*7c478bd9Sstevel@tonic-gate 	static char w_badopt[] = "option '%s' unrecognized, ignoring";
2397*7c478bd9Sstevel@tonic-gate 	static char w_newline[] = "rule is incomplete";
2398*7c478bd9Sstevel@tonic-gate 	static char w_insert[] = "failed to register rule";
2399*7c478bd9Sstevel@tonic-gate 	static char w_comment[] = "'#' not allowed except at start of line";
2400*7c478bd9Sstevel@tonic-gate 	static char w_dupargs[] =
2401*7c478bd9Sstevel@tonic-gate 	    "argument '%s' duplicates a previous argument, skipping";
2402*7c478bd9Sstevel@tonic-gate 	static char w_nt_empty[] = "empty device specification not allowed";
2403*7c478bd9Sstevel@tonic-gate 
2404*7c478bd9Sstevel@tonic-gate 	if (filename == NULL) {
2405*7c478bd9Sstevel@tonic-gate 		fname = dacffile;	/* default binding file */
2406*7c478bd9Sstevel@tonic-gate 	} else {
2407*7c478bd9Sstevel@tonic-gate 		fname = filename;	/* user specified */
2408*7c478bd9Sstevel@tonic-gate 	}
2409*7c478bd9Sstevel@tonic-gate 
2410*7c478bd9Sstevel@tonic-gate 	if ((file = kobj_open_file(fname)) == (struct _buf *)-1) {
2411*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
2412*7c478bd9Sstevel@tonic-gate 	}
2413*7c478bd9Sstevel@tonic-gate 
2414*7c478bd9Sstevel@tonic-gate 	if (dacfdebug & DACF_DBG_MSGS) {
2415*7c478bd9Sstevel@tonic-gate 		printf("dacf debug: clearing rules database\n");
2416*7c478bd9Sstevel@tonic-gate 	}
2417*7c478bd9Sstevel@tonic-gate 
2418*7c478bd9Sstevel@tonic-gate 	mutex_enter(&dacf_lock);
2419*7c478bd9Sstevel@tonic-gate 	dacf_clear_rules();
2420*7c478bd9Sstevel@tonic-gate 
2421*7c478bd9Sstevel@tonic-gate 	if (dacfdebug & DACF_DBG_MSGS) {
2422*7c478bd9Sstevel@tonic-gate 		printf("dacf debug: parsing %s\n", fname);
2423*7c478bd9Sstevel@tonic-gate 	}
2424*7c478bd9Sstevel@tonic-gate 
2425*7c478bd9Sstevel@tonic-gate 	while (!done) {
2426*7c478bd9Sstevel@tonic-gate 		token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate 		switch (token) {
2429*7c478bd9Sstevel@tonic-gate 		case POUND:	/* comment line */
2430*7c478bd9Sstevel@tonic-gate 			if (state != DACF_BEGIN) {
2431*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_comment);
2432*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR;
2433*7c478bd9Sstevel@tonic-gate 				break;
2434*7c478bd9Sstevel@tonic-gate 			}
2435*7c478bd9Sstevel@tonic-gate 			state = DACF_COMMENT;
2436*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
2437*7c478bd9Sstevel@tonic-gate 			break;
2438*7c478bd9Sstevel@tonic-gate 
2439*7c478bd9Sstevel@tonic-gate 		case EQUALS:
2440*7c478bd9Sstevel@tonic-gate 			switch (state) {
2441*7c478bd9Sstevel@tonic-gate 			case DACF_NT_SPEC:
2442*7c478bd9Sstevel@tonic-gate 				state = DACF_NT_EQUALS;
2443*7c478bd9Sstevel@tonic-gate 				break;
2444*7c478bd9Sstevel@tonic-gate 			case DACF_OPARG_SPEC:
2445*7c478bd9Sstevel@tonic-gate 				state = DACF_OPARG_EQUALS;
2446*7c478bd9Sstevel@tonic-gate 				break;
2447*7c478bd9Sstevel@tonic-gate 			default:
2448*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_equals);
2449*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR;
2450*7c478bd9Sstevel@tonic-gate 			}
2451*7c478bd9Sstevel@tonic-gate 			break;
2452*7c478bd9Sstevel@tonic-gate 
2453*7c478bd9Sstevel@tonic-gate 		case NAME:
2454*7c478bd9Sstevel@tonic-gate 			switch (state) {
2455*7c478bd9Sstevel@tonic-gate 			case DACF_BEGIN:
2456*7c478bd9Sstevel@tonic-gate 				nt_spec_type = dacf_get_devspec(tokbuf);
2457*7c478bd9Sstevel@tonic-gate 				if (nt_spec_type == DACF_DS_ERROR) {
2458*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
2459*7c478bd9Sstevel@tonic-gate 					    w_baddevspec, tokbuf);
2460*7c478bd9Sstevel@tonic-gate 					state = DACF_ERR;
2461*7c478bd9Sstevel@tonic-gate 					break;
2462*7c478bd9Sstevel@tonic-gate 				}
2463*7c478bd9Sstevel@tonic-gate 				state = DACF_NT_SPEC;
2464*7c478bd9Sstevel@tonic-gate 				break;
2465*7c478bd9Sstevel@tonic-gate 			case DACF_NT_DATA:
2466*7c478bd9Sstevel@tonic-gate 				(void) strncpy(mn_modname_buf, tokbuf,
2467*7c478bd9Sstevel@tonic-gate 				    sizeof (mn_modname_buf));
2468*7c478bd9Sstevel@tonic-gate 				mn_modnamep = mn_modname_buf;
2469*7c478bd9Sstevel@tonic-gate 				state = DACF_MN_MODNAME;
2470*7c478bd9Sstevel@tonic-gate 				break;
2471*7c478bd9Sstevel@tonic-gate 			case DACF_MN_MODNAME:
2472*7c478bd9Sstevel@tonic-gate 				/*
2473*7c478bd9Sstevel@tonic-gate 				 * This handles the 'optional' modname.
2474*7c478bd9Sstevel@tonic-gate 				 * What we thought was the modname is really
2475*7c478bd9Sstevel@tonic-gate 				 * the op-set.  So it is copied over.
2476*7c478bd9Sstevel@tonic-gate 				 */
2477*7c478bd9Sstevel@tonic-gate 				ASSERT(mn_modnamep);
2478*7c478bd9Sstevel@tonic-gate 				(void) strncpy(mn_opset_buf, mn_modnamep,
2479*7c478bd9Sstevel@tonic-gate 				    sizeof (mn_opset_buf));
2480*7c478bd9Sstevel@tonic-gate 				mn_opsetp = mn_opset_buf;
2481*7c478bd9Sstevel@tonic-gate 				mn_modnamep = NULL;
2482*7c478bd9Sstevel@tonic-gate 				/*
2483*7c478bd9Sstevel@tonic-gate 				 * Now, the token we just read is the opset,
2484*7c478bd9Sstevel@tonic-gate 				 * so look that up and fill in opid
2485*7c478bd9Sstevel@tonic-gate 				 */
2486*7c478bd9Sstevel@tonic-gate 				if ((opid = dacf_get_op(tokbuf)) ==
2487*7c478bd9Sstevel@tonic-gate 				    DACF_OPID_ERROR) {
2488*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, w_badop,
2489*7c478bd9Sstevel@tonic-gate 					    tokbuf);
2490*7c478bd9Sstevel@tonic-gate 					state = DACF_ERR;
2491*7c478bd9Sstevel@tonic-gate 					break;
2492*7c478bd9Sstevel@tonic-gate 				}
2493*7c478bd9Sstevel@tonic-gate 				state = DACF_OP_NAME;
2494*7c478bd9Sstevel@tonic-gate 				break;
2495*7c478bd9Sstevel@tonic-gate 			case DACF_MN_COLON:
2496*7c478bd9Sstevel@tonic-gate 				(void) strncpy(mn_opset_buf, tokbuf,
2497*7c478bd9Sstevel@tonic-gate 				    sizeof (mn_opset_buf));
2498*7c478bd9Sstevel@tonic-gate 				mn_opsetp = mn_opset_buf;
2499*7c478bd9Sstevel@tonic-gate 				state = DACF_MN_OPSET;
2500*7c478bd9Sstevel@tonic-gate 				break;
2501*7c478bd9Sstevel@tonic-gate 			case DACF_MN_OPSET:
2502*7c478bd9Sstevel@tonic-gate 				if ((opid = dacf_get_op(tokbuf)) ==
2503*7c478bd9Sstevel@tonic-gate 				    DACF_OPID_ERROR) {
2504*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, w_badop,
2505*7c478bd9Sstevel@tonic-gate 					    tokbuf);
2506*7c478bd9Sstevel@tonic-gate 					state = DACF_ERR;
2507*7c478bd9Sstevel@tonic-gate 					break;
2508*7c478bd9Sstevel@tonic-gate 				}
2509*7c478bd9Sstevel@tonic-gate 				state = DACF_OP_NAME;
2510*7c478bd9Sstevel@tonic-gate 				break;
2511*7c478bd9Sstevel@tonic-gate 			case DACF_OP_NAME:
2512*7c478bd9Sstevel@tonic-gate 				/*
2513*7c478bd9Sstevel@tonic-gate 				 * This case is just like DACF_OPT_COMMA below,
2514*7c478bd9Sstevel@tonic-gate 				 * but we check for the sole '-' argument
2515*7c478bd9Sstevel@tonic-gate 				 */
2516*7c478bd9Sstevel@tonic-gate 				if (strcmp(tokbuf, "-") == 0) {
2517*7c478bd9Sstevel@tonic-gate 					state = DACF_OPT_END;
2518*7c478bd9Sstevel@tonic-gate 					break;
2519*7c478bd9Sstevel@tonic-gate 				}
2520*7c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
2521*7c478bd9Sstevel@tonic-gate 			case DACF_OPT_COMMA:
2522*7c478bd9Sstevel@tonic-gate 				/*
2523*7c478bd9Sstevel@tonic-gate 				 * figure out what option was given, but don't
2524*7c478bd9Sstevel@tonic-gate 				 * make a federal case if invalid, just skip it
2525*7c478bd9Sstevel@tonic-gate 				 */
2526*7c478bd9Sstevel@tonic-gate 				if (dacf_getopt(tokbuf, &opts) != 0) {
2527*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, w_badopt,
2528*7c478bd9Sstevel@tonic-gate 					    tokbuf);
2529*7c478bd9Sstevel@tonic-gate 				}
2530*7c478bd9Sstevel@tonic-gate 				state = DACF_OPT_OPTION;
2531*7c478bd9Sstevel@tonic-gate 				break;
2532*7c478bd9Sstevel@tonic-gate 			case DACF_OPT_END:
2533*7c478bd9Sstevel@tonic-gate 			case DACF_OPT_OPTION:
2534*7c478bd9Sstevel@tonic-gate 			case DACF_OPARG_DATA:
2535*7c478bd9Sstevel@tonic-gate 				(void) strncpy(arg_spec_buf, tokbuf,
2536*7c478bd9Sstevel@tonic-gate 				    sizeof (arg_spec_buf));
2537*7c478bd9Sstevel@tonic-gate 				state = DACF_OPARG_SPEC;
2538*7c478bd9Sstevel@tonic-gate 				break;
2539*7c478bd9Sstevel@tonic-gate 			case DACF_OPARG_EQUALS:
2540*7c478bd9Sstevel@tonic-gate 				/*
2541*7c478bd9Sstevel@tonic-gate 				 * Add the arg.  Warn if it's a duplicate
2542*7c478bd9Sstevel@tonic-gate 				 */
2543*7c478bd9Sstevel@tonic-gate 				if (dacf_arg_insert(&arg_list, arg_spec_buf,
2544*7c478bd9Sstevel@tonic-gate 				    tokbuf) != 0) {
2545*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, w_dupargs,
2546*7c478bd9Sstevel@tonic-gate 					    arg_spec_buf);
2547*7c478bd9Sstevel@tonic-gate 				}
2548*7c478bd9Sstevel@tonic-gate 				state = DACF_OPARG_DATA;
2549*7c478bd9Sstevel@tonic-gate 				break;
2550*7c478bd9Sstevel@tonic-gate 			default:
2551*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_syntax, tokbuf);
2552*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR;
2553*7c478bd9Sstevel@tonic-gate 				break;
2554*7c478bd9Sstevel@tonic-gate 			}
2555*7c478bd9Sstevel@tonic-gate 			break;
2556*7c478bd9Sstevel@tonic-gate 
2557*7c478bd9Sstevel@tonic-gate 		case STRING:
2558*7c478bd9Sstevel@tonic-gate 			/*
2559*7c478bd9Sstevel@tonic-gate 			 * We need to check to see if the string has a \n in it.
2560*7c478bd9Sstevel@tonic-gate 			 * If so, we had an unmatched " mark error, and lex has
2561*7c478bd9Sstevel@tonic-gate 			 * already emitted an error for us, so we need to enter
2562*7c478bd9Sstevel@tonic-gate 			 * the error state.  Stupid lex.
2563*7c478bd9Sstevel@tonic-gate 			 */
2564*7c478bd9Sstevel@tonic-gate 			if (strchr(tokbuf, '\n')) {
2565*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR;
2566*7c478bd9Sstevel@tonic-gate 				break;
2567*7c478bd9Sstevel@tonic-gate 			}
2568*7c478bd9Sstevel@tonic-gate 			switch (state) {
2569*7c478bd9Sstevel@tonic-gate 			case DACF_NT_EQUALS:
2570*7c478bd9Sstevel@tonic-gate 				if (strlen(tokbuf) == 0) {
2571*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
2572*7c478bd9Sstevel@tonic-gate 					    w_nt_empty);
2573*7c478bd9Sstevel@tonic-gate 					state = DACF_ERR;
2574*7c478bd9Sstevel@tonic-gate 					break;
2575*7c478bd9Sstevel@tonic-gate 				}
2576*7c478bd9Sstevel@tonic-gate 				state = DACF_NT_DATA;
2577*7c478bd9Sstevel@tonic-gate 				nt_datap = nt_data_buf;
2578*7c478bd9Sstevel@tonic-gate 				(void) strncpy(nt_datap, tokbuf,
2579*7c478bd9Sstevel@tonic-gate 				    sizeof (nt_data_buf));
2580*7c478bd9Sstevel@tonic-gate 				break;
2581*7c478bd9Sstevel@tonic-gate 			case DACF_OPARG_EQUALS:
2582*7c478bd9Sstevel@tonic-gate 				/*
2583*7c478bd9Sstevel@tonic-gate 				 * Add the arg.  Warn if it's a duplicate
2584*7c478bd9Sstevel@tonic-gate 				 */
2585*7c478bd9Sstevel@tonic-gate 				if (dacf_arg_insert(&arg_list, arg_spec_buf,
2586*7c478bd9Sstevel@tonic-gate 				    tokbuf) != 0) {
2587*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file, w_dupargs,
2588*7c478bd9Sstevel@tonic-gate 					    arg_spec_buf);
2589*7c478bd9Sstevel@tonic-gate 				}
2590*7c478bd9Sstevel@tonic-gate 				state = DACF_OPARG_DATA;
2591*7c478bd9Sstevel@tonic-gate 				break;
2592*7c478bd9Sstevel@tonic-gate 			default:
2593*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_syntax, tokbuf);
2594*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR;
2595*7c478bd9Sstevel@tonic-gate 				break;
2596*7c478bd9Sstevel@tonic-gate 			}
2597*7c478bd9Sstevel@tonic-gate 			break;
2598*7c478bd9Sstevel@tonic-gate 
2599*7c478bd9Sstevel@tonic-gate 		case COMMA:
2600*7c478bd9Sstevel@tonic-gate 			switch (state) {
2601*7c478bd9Sstevel@tonic-gate 			case DACF_OPT_OPTION:
2602*7c478bd9Sstevel@tonic-gate 				state = DACF_OPT_COMMA;
2603*7c478bd9Sstevel@tonic-gate 				break;
2604*7c478bd9Sstevel@tonic-gate 			default:
2605*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_syntax, ",");
2606*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR;
2607*7c478bd9Sstevel@tonic-gate 				break;
2608*7c478bd9Sstevel@tonic-gate 			}
2609*7c478bd9Sstevel@tonic-gate 			break;
2610*7c478bd9Sstevel@tonic-gate 
2611*7c478bd9Sstevel@tonic-gate 		case COLON:
2612*7c478bd9Sstevel@tonic-gate 			if (state == DACF_MN_MODNAME)
2613*7c478bd9Sstevel@tonic-gate 				state = DACF_MN_COLON;
2614*7c478bd9Sstevel@tonic-gate 			else {
2615*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_syntax, ":");
2616*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR;
2617*7c478bd9Sstevel@tonic-gate 			}
2618*7c478bd9Sstevel@tonic-gate 			break;
2619*7c478bd9Sstevel@tonic-gate 
2620*7c478bd9Sstevel@tonic-gate 		case EOF:
2621*7c478bd9Sstevel@tonic-gate 			done = 1;
2622*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
2623*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
2624*7c478bd9Sstevel@tonic-gate 			if (state == DACF_COMMENT || state == DACF_BEGIN) {
2625*7c478bd9Sstevel@tonic-gate 				state = DACF_BEGIN;
2626*7c478bd9Sstevel@tonic-gate 				kobj_newline(file);
2627*7c478bd9Sstevel@tonic-gate 				break;
2628*7c478bd9Sstevel@tonic-gate 			}
2629*7c478bd9Sstevel@tonic-gate 			if ((state != DACF_OPT_OPTION) &&
2630*7c478bd9Sstevel@tonic-gate 			    (state != DACF_OPARG_DATA) &&
2631*7c478bd9Sstevel@tonic-gate 			    (state != DACF_OPT_END)) {
2632*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_newline);
2633*7c478bd9Sstevel@tonic-gate 				/*
2634*7c478bd9Sstevel@tonic-gate 				 * We can't just do DACF_ERR here, since we'll
2635*7c478bd9Sstevel@tonic-gate 				 * wind up eating the _next_ newline if so.
2636*7c478bd9Sstevel@tonic-gate 				 */
2637*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR_NEWLINE;
2638*7c478bd9Sstevel@tonic-gate 				kobj_newline(file);
2639*7c478bd9Sstevel@tonic-gate 				break;
2640*7c478bd9Sstevel@tonic-gate 			}
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate 			/*
2643*7c478bd9Sstevel@tonic-gate 			 * insert the rule.
2644*7c478bd9Sstevel@tonic-gate 			 */
2645*7c478bd9Sstevel@tonic-gate 			if (dacf_rule_insert(nt_spec_type, nt_datap,
2646*7c478bd9Sstevel@tonic-gate 			    mn_modnamep, mn_opsetp, opid, opts, arg_list) < 0) {
2647*7c478bd9Sstevel@tonic-gate 				/*
2648*7c478bd9Sstevel@tonic-gate 				 * We can't just do DACF_ERR here, since we'll
2649*7c478bd9Sstevel@tonic-gate 				 * wind up eating the _next_ newline if so.
2650*7c478bd9Sstevel@tonic-gate 				 */
2651*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, w_insert);
2652*7c478bd9Sstevel@tonic-gate 				state = DACF_ERR_NEWLINE;
2653*7c478bd9Sstevel@tonic-gate 				kobj_newline(file);
2654*7c478bd9Sstevel@tonic-gate 				break;
2655*7c478bd9Sstevel@tonic-gate 			}
2656*7c478bd9Sstevel@tonic-gate 
2657*7c478bd9Sstevel@tonic-gate 			state = DACF_BEGIN;
2658*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
2659*7c478bd9Sstevel@tonic-gate 			break;
2660*7c478bd9Sstevel@tonic-gate 
2661*7c478bd9Sstevel@tonic-gate 		default:
2662*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, w_syntax, tokbuf);
2663*7c478bd9Sstevel@tonic-gate 			break;
2664*7c478bd9Sstevel@tonic-gate 		} /* switch */
2665*7c478bd9Sstevel@tonic-gate 
2666*7c478bd9Sstevel@tonic-gate 		/*
2667*7c478bd9Sstevel@tonic-gate 		 * Clean up after ourselves, either after a line has terminated
2668*7c478bd9Sstevel@tonic-gate 		 * successfully or because of a syntax error; or when we reach
2669*7c478bd9Sstevel@tonic-gate 		 * EOF (remember, we may reach EOF without being 'done' with
2670*7c478bd9Sstevel@tonic-gate 		 * handling a particular line).
2671*7c478bd9Sstevel@tonic-gate 		 */
2672*7c478bd9Sstevel@tonic-gate 		if (state == DACF_ERR) {
2673*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
2674*7c478bd9Sstevel@tonic-gate 		}
2675*7c478bd9Sstevel@tonic-gate 		if ((state == DACF_BEGIN) || (state == DACF_ERR) ||
2676*7c478bd9Sstevel@tonic-gate 		    (state == DACF_ERR_NEWLINE) || done) {
2677*7c478bd9Sstevel@tonic-gate 			nt_datap = NULL;
2678*7c478bd9Sstevel@tonic-gate 			mn_modnamep = mn_opsetp = NULL;
2679*7c478bd9Sstevel@tonic-gate 			opts = 0;
2680*7c478bd9Sstevel@tonic-gate 			opid = DACF_OPID_ERROR;
2681*7c478bd9Sstevel@tonic-gate 			nt_spec_type = DACF_DS_ERROR;
2682*7c478bd9Sstevel@tonic-gate 			dacf_arglist_delete(&arg_list);
2683*7c478bd9Sstevel@tonic-gate 			state = DACF_BEGIN;
2684*7c478bd9Sstevel@tonic-gate 		}
2685*7c478bd9Sstevel@tonic-gate 	} /* while */
2686*7c478bd9Sstevel@tonic-gate 
2687*7c478bd9Sstevel@tonic-gate 	if (dacfdebug & DACF_DBG_MSGS) {
2688*7c478bd9Sstevel@tonic-gate 		printf("\ndacf debug: done!\n");
2689*7c478bd9Sstevel@tonic-gate 	}
2690*7c478bd9Sstevel@tonic-gate 
2691*7c478bd9Sstevel@tonic-gate 	mutex_exit(&dacf_lock);
2692*7c478bd9Sstevel@tonic-gate 
2693*7c478bd9Sstevel@tonic-gate 	kobj_close_file(file);
2694*7c478bd9Sstevel@tonic-gate 	return (0);
2695*7c478bd9Sstevel@tonic-gate }
2696*7c478bd9Sstevel@tonic-gate 
2697*7c478bd9Sstevel@tonic-gate void
2698*7c478bd9Sstevel@tonic-gate lock_hw_class_list()
2699*7c478bd9Sstevel@tonic-gate {
2700*7c478bd9Sstevel@tonic-gate 	mutex_enter(&hcl_lock);
2701*7c478bd9Sstevel@tonic-gate }
2702*7c478bd9Sstevel@tonic-gate 
2703*7c478bd9Sstevel@tonic-gate void
2704*7c478bd9Sstevel@tonic-gate unlock_hw_class_list()
2705*7c478bd9Sstevel@tonic-gate {
2706*7c478bd9Sstevel@tonic-gate 	mutex_exit(&hcl_lock);
2707*7c478bd9Sstevel@tonic-gate }
2708*7c478bd9Sstevel@tonic-gate 
2709*7c478bd9Sstevel@tonic-gate void
2710*7c478bd9Sstevel@tonic-gate add_class(char *exporter, char *class)
2711*7c478bd9Sstevel@tonic-gate {
2712*7c478bd9Sstevel@tonic-gate 	struct hwc_class *hcl;
2713*7c478bd9Sstevel@tonic-gate 
2714*7c478bd9Sstevel@tonic-gate 	/*
2715*7c478bd9Sstevel@tonic-gate 	 * If exporter's major is not registered in /etc/name_to_major,
2716*7c478bd9Sstevel@tonic-gate 	 * don't update hwc_class, but just return here.
2717*7c478bd9Sstevel@tonic-gate 	 */
2718*7c478bd9Sstevel@tonic-gate 	if (ddi_name_to_major(exporter) >= devcnt) {
2719*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "No major number for driver %s"
2720*7c478bd9Sstevel@tonic-gate 				" in class %s", exporter, class);
2721*7c478bd9Sstevel@tonic-gate 		return;
2722*7c478bd9Sstevel@tonic-gate 	}
2723*7c478bd9Sstevel@tonic-gate 	hcl = kmem_zalloc(sizeof (struct hwc_class), KM_SLEEP);
2724*7c478bd9Sstevel@tonic-gate 	hcl->class_exporter = kmem_alloc(strlen(exporter) + 1, KM_SLEEP);
2725*7c478bd9Sstevel@tonic-gate 	hcl->class_name = kmem_alloc(strlen(class) + 1, KM_SLEEP);
2726*7c478bd9Sstevel@tonic-gate 	(void) strcpy(hcl->class_exporter, exporter);
2727*7c478bd9Sstevel@tonic-gate 	(void) strcpy(hcl->class_name, class);
2728*7c478bd9Sstevel@tonic-gate 	lock_hw_class_list();
2729*7c478bd9Sstevel@tonic-gate 	hcl->class_next = hcl_head;
2730*7c478bd9Sstevel@tonic-gate 	hcl_head = hcl;
2731*7c478bd9Sstevel@tonic-gate 	unlock_hw_class_list();
2732*7c478bd9Sstevel@tonic-gate }
2733*7c478bd9Sstevel@tonic-gate 
2734*7c478bd9Sstevel@tonic-gate /*
2735*7c478bd9Sstevel@tonic-gate  * Return the number of classes exported. If buf is not NULL, fill in
2736*7c478bd9Sstevel@tonic-gate  * the array of the class names as well.
2737*7c478bd9Sstevel@tonic-gate  *
2738*7c478bd9Sstevel@tonic-gate  * Caller must hold hcl_lock to ensure the class list unmodified while
2739*7c478bd9Sstevel@tonic-gate  * it is accessed. A typical caller will get a count first and then
2740*7c478bd9Sstevel@tonic-gate  * allocate buf. The lock should be held by the caller.
2741*7c478bd9Sstevel@tonic-gate  */
2742*7c478bd9Sstevel@tonic-gate int
2743*7c478bd9Sstevel@tonic-gate get_class(const char *exporter, char **buf)
2744*7c478bd9Sstevel@tonic-gate {
2745*7c478bd9Sstevel@tonic-gate 	int n = 0;
2746*7c478bd9Sstevel@tonic-gate 	struct hwc_class *hcl;
2747*7c478bd9Sstevel@tonic-gate 
2748*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&hcl_lock));
2749*7c478bd9Sstevel@tonic-gate 	for (hcl = hcl_head; hcl != NULL; hcl = hcl->class_next) {
2750*7c478bd9Sstevel@tonic-gate 		if (strcmp(exporter, hcl->class_exporter) == 0) {
2751*7c478bd9Sstevel@tonic-gate 			if (buf)
2752*7c478bd9Sstevel@tonic-gate 				buf[n] = hcl->class_name;
2753*7c478bd9Sstevel@tonic-gate 			++n;
2754*7c478bd9Sstevel@tonic-gate 		}
2755*7c478bd9Sstevel@tonic-gate 	}
2756*7c478bd9Sstevel@tonic-gate 
2757*7c478bd9Sstevel@tonic-gate 	return (n);
2758*7c478bd9Sstevel@tonic-gate }
2759*7c478bd9Sstevel@tonic-gate 
2760*7c478bd9Sstevel@tonic-gate void
2761*7c478bd9Sstevel@tonic-gate read_class_file(void)
2762*7c478bd9Sstevel@tonic-gate {
2763*7c478bd9Sstevel@tonic-gate 	struct _buf *file;
2764*7c478bd9Sstevel@tonic-gate 	struct hwc_class *hcl, *hcl1;
2765*7c478bd9Sstevel@tonic-gate 	char tokbuf[MAXNAMELEN];
2766*7c478bd9Sstevel@tonic-gate 	enum {
2767*7c478bd9Sstevel@tonic-gate 		C_BEGIN, C_EXPORTER, C_END
2768*7c478bd9Sstevel@tonic-gate 	} state;
2769*7c478bd9Sstevel@tonic-gate 	token_t token;
2770*7c478bd9Sstevel@tonic-gate 	int done = 0;
2771*7c478bd9Sstevel@tonic-gate 	char *exporter = NULL, *class = NULL, *name = NULL;
2772*7c478bd9Sstevel@tonic-gate 
2773*7c478bd9Sstevel@tonic-gate 	if (hcl_head != NULL) {
2774*7c478bd9Sstevel@tonic-gate 		hcl = hcl_head;
2775*7c478bd9Sstevel@tonic-gate 		while (hcl != NULL) {
2776*7c478bd9Sstevel@tonic-gate 			kmem_free(hcl->class_exporter,
2777*7c478bd9Sstevel@tonic-gate 			    strlen(hcl->class_exporter) + 1);
2778*7c478bd9Sstevel@tonic-gate 			hcl1 = hcl;
2779*7c478bd9Sstevel@tonic-gate 			hcl = hcl->class_next;
2780*7c478bd9Sstevel@tonic-gate 			kmem_free(hcl1, sizeof (struct hwc_class));
2781*7c478bd9Sstevel@tonic-gate 		}
2782*7c478bd9Sstevel@tonic-gate 		hcl_head = NULL;
2783*7c478bd9Sstevel@tonic-gate 	}
2784*7c478bd9Sstevel@tonic-gate 
2785*7c478bd9Sstevel@tonic-gate 	if ((file = kobj_open_file(class_file)) == (struct _buf *)-1)
2786*7c478bd9Sstevel@tonic-gate 		return;
2787*7c478bd9Sstevel@tonic-gate 
2788*7c478bd9Sstevel@tonic-gate 	state = C_BEGIN;
2789*7c478bd9Sstevel@tonic-gate 	while (!done) {
2790*7c478bd9Sstevel@tonic-gate 		token = kobj_lex(file, tokbuf, sizeof (tokbuf));
2791*7c478bd9Sstevel@tonic-gate 
2792*7c478bd9Sstevel@tonic-gate 		switch (token) {
2793*7c478bd9Sstevel@tonic-gate 		case POUND:
2794*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
2795*7c478bd9Sstevel@tonic-gate 			break;
2796*7c478bd9Sstevel@tonic-gate 		case NAME:
2797*7c478bd9Sstevel@tonic-gate 		case STRING:
2798*7c478bd9Sstevel@tonic-gate 			name = kmem_alloc(strlen(tokbuf) + 1, KM_SLEEP);
2799*7c478bd9Sstevel@tonic-gate 			(void) strcpy(name, tokbuf);
2800*7c478bd9Sstevel@tonic-gate 			switch (state) {
2801*7c478bd9Sstevel@tonic-gate 			case C_BEGIN:
2802*7c478bd9Sstevel@tonic-gate 				exporter = name;
2803*7c478bd9Sstevel@tonic-gate 				state = C_EXPORTER;
2804*7c478bd9Sstevel@tonic-gate 				break;
2805*7c478bd9Sstevel@tonic-gate 			case C_EXPORTER:
2806*7c478bd9Sstevel@tonic-gate 				class = name;
2807*7c478bd9Sstevel@tonic-gate 				add_class(exporter, class);
2808*7c478bd9Sstevel@tonic-gate 				state = C_END;
2809*7c478bd9Sstevel@tonic-gate 				break;
2810*7c478bd9Sstevel@tonic-gate 			case C_END:
2811*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
2812*7c478bd9Sstevel@tonic-gate 				    "Extra noise after entry");
2813*7c478bd9Sstevel@tonic-gate 				kmem_free(name, strlen(name) + 1);
2814*7c478bd9Sstevel@tonic-gate 				kobj_find_eol(file);
2815*7c478bd9Sstevel@tonic-gate 				break;
2816*7c478bd9Sstevel@tonic-gate 			} /* End Switch */
2817*7c478bd9Sstevel@tonic-gate 			break;
2818*7c478bd9Sstevel@tonic-gate 		case EOF:
2819*7c478bd9Sstevel@tonic-gate 			done = 1;
2820*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
2821*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
2822*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
2823*7c478bd9Sstevel@tonic-gate 			if (state == C_EXPORTER)
2824*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
2825*7c478bd9Sstevel@tonic-gate 				    "Partial entry ignored");
2826*7c478bd9Sstevel@tonic-gate 			state = C_BEGIN;
2827*7c478bd9Sstevel@tonic-gate 			if (exporter)
2828*7c478bd9Sstevel@tonic-gate 				kmem_free(exporter, strlen(exporter) + 1);
2829*7c478bd9Sstevel@tonic-gate 			if (class)
2830*7c478bd9Sstevel@tonic-gate 				kmem_free(class, strlen(class) + 1);
2831*7c478bd9Sstevel@tonic-gate 			exporter = NULL;
2832*7c478bd9Sstevel@tonic-gate 			class = NULL;
2833*7c478bd9Sstevel@tonic-gate 			break;
2834*7c478bd9Sstevel@tonic-gate 		default:
2835*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2836*7c478bd9Sstevel@tonic-gate 			break;
2837*7c478bd9Sstevel@tonic-gate 		}
2838*7c478bd9Sstevel@tonic-gate 	}
2839*7c478bd9Sstevel@tonic-gate 	kobj_close_file(file);
2840*7c478bd9Sstevel@tonic-gate }
2841*7c478bd9Sstevel@tonic-gate 
2842*7c478bd9Sstevel@tonic-gate /*
2843*7c478bd9Sstevel@tonic-gate  * Given par_list, get a list of parent major number
2844*7c478bd9Sstevel@tonic-gate  */
2845*7c478bd9Sstevel@tonic-gate int
2846*7c478bd9Sstevel@tonic-gate impl_parlist_to_major(struct par_list *pl, char parents[])
2847*7c478bd9Sstevel@tonic-gate {
2848*7c478bd9Sstevel@tonic-gate 	struct hwc_spec *hwcp;
2849*7c478bd9Sstevel@tonic-gate 	struct hwc_class *hcl;
2850*7c478bd9Sstevel@tonic-gate 	major_t major;
2851*7c478bd9Sstevel@tonic-gate 	int nmajor = 0;
2852*7c478bd9Sstevel@tonic-gate 	extern int devcnt;
2853*7c478bd9Sstevel@tonic-gate 
2854*7c478bd9Sstevel@tonic-gate 	for (; pl != NULL; pl = pl->par_next) {
2855*7c478bd9Sstevel@tonic-gate 		if ((pl->par_major < devcnt) && (parents[pl->par_major] == 0)) {
2856*7c478bd9Sstevel@tonic-gate 			parents[pl->par_major] = 1;
2857*7c478bd9Sstevel@tonic-gate 			nmajor++;
2858*7c478bd9Sstevel@tonic-gate 			continue;
2859*7c478bd9Sstevel@tonic-gate 		}
2860*7c478bd9Sstevel@tonic-gate 
2861*7c478bd9Sstevel@tonic-gate 		/* parent specs cannot be mapped to a driver */
2862*7c478bd9Sstevel@tonic-gate 		if (pl->par_major != (major_t)-1)
2863*7c478bd9Sstevel@tonic-gate 			continue;
2864*7c478bd9Sstevel@tonic-gate 
2865*7c478bd9Sstevel@tonic-gate 		/* class spec */
2866*7c478bd9Sstevel@tonic-gate 		hwcp = pl->par_specs;
2867*7c478bd9Sstevel@tonic-gate 		ASSERT(hwcp->hwc_class_name);
2868*7c478bd9Sstevel@tonic-gate 		ASSERT(hwcp->hwc_parent_name == NULL);
2869*7c478bd9Sstevel@tonic-gate 
2870*7c478bd9Sstevel@tonic-gate 		for (hcl = hcl_head; hcl != NULL; hcl = hcl->class_next) {
2871*7c478bd9Sstevel@tonic-gate 			if (strcmp(hwcp->hwc_class_name, hcl->class_name) != 0)
2872*7c478bd9Sstevel@tonic-gate 				continue;
2873*7c478bd9Sstevel@tonic-gate 			major = ddi_name_to_major(hcl->class_exporter);
2874*7c478bd9Sstevel@tonic-gate 			ASSERT(major != (major_t)-1);
2875*7c478bd9Sstevel@tonic-gate 			if (parents[major] == 0) {
2876*7c478bd9Sstevel@tonic-gate 				parents[major] = 1;
2877*7c478bd9Sstevel@tonic-gate 				nmajor++;
2878*7c478bd9Sstevel@tonic-gate 			}
2879*7c478bd9Sstevel@tonic-gate 		}
2880*7c478bd9Sstevel@tonic-gate 	}
2881*7c478bd9Sstevel@tonic-gate 	return (nmajor);
2882*7c478bd9Sstevel@tonic-gate }
2883*7c478bd9Sstevel@tonic-gate 
2884*7c478bd9Sstevel@tonic-gate /*
2885*7c478bd9Sstevel@tonic-gate  * delete a parent list and all its hwc specs
2886*7c478bd9Sstevel@tonic-gate  */
2887*7c478bd9Sstevel@tonic-gate void
2888*7c478bd9Sstevel@tonic-gate impl_delete_par_list(struct par_list *pl)
2889*7c478bd9Sstevel@tonic-gate {
2890*7c478bd9Sstevel@tonic-gate 	struct par_list *saved_pl;
2891*7c478bd9Sstevel@tonic-gate 	struct hwc_spec *hp, *hp1;
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	while (pl) {
2894*7c478bd9Sstevel@tonic-gate 		hp = pl->par_specs;
2895*7c478bd9Sstevel@tonic-gate 		while (hp) {
2896*7c478bd9Sstevel@tonic-gate 			hp1 = hp;
2897*7c478bd9Sstevel@tonic-gate 			hp = hp->hwc_next;
2898*7c478bd9Sstevel@tonic-gate 			hwc_free(hp1);
2899*7c478bd9Sstevel@tonic-gate 		}
2900*7c478bd9Sstevel@tonic-gate 		saved_pl = pl;
2901*7c478bd9Sstevel@tonic-gate 		pl = pl->par_next;
2902*7c478bd9Sstevel@tonic-gate 		kmem_free(saved_pl, sizeof (*saved_pl));
2903*7c478bd9Sstevel@tonic-gate 	}
2904*7c478bd9Sstevel@tonic-gate }
2905*7c478bd9Sstevel@tonic-gate 
2906*7c478bd9Sstevel@tonic-gate #if defined(_PSM_MODULES)
2907*7c478bd9Sstevel@tonic-gate void
2908*7c478bd9Sstevel@tonic-gate open_mach_list(void)
2909*7c478bd9Sstevel@tonic-gate {
2910*7c478bd9Sstevel@tonic-gate 	struct _buf *file;
2911*7c478bd9Sstevel@tonic-gate 	char tokbuf[MAXNAMELEN];
2912*7c478bd9Sstevel@tonic-gate 	token_t token;
2913*7c478bd9Sstevel@tonic-gate 	struct psm_mach *machp;
2914*7c478bd9Sstevel@tonic-gate 
2915*7c478bd9Sstevel@tonic-gate 	if ((file = kobj_open_file(mach_file)) == (struct _buf *)-1)
2916*7c478bd9Sstevel@tonic-gate 		return;
2917*7c478bd9Sstevel@tonic-gate 
2918*7c478bd9Sstevel@tonic-gate 	while ((token = kobj_lex(file, tokbuf, sizeof (tokbuf))) != EOF) {
2919*7c478bd9Sstevel@tonic-gate 		switch (token) {
2920*7c478bd9Sstevel@tonic-gate 		case POUND:
2921*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
2922*7c478bd9Sstevel@tonic-gate 			break;
2923*7c478bd9Sstevel@tonic-gate 		case NAME:
2924*7c478bd9Sstevel@tonic-gate 		case STRING:
2925*7c478bd9Sstevel@tonic-gate 			machp = kmem_alloc((sizeof (struct psm_mach) +
2926*7c478bd9Sstevel@tonic-gate 			    strlen(tokbuf) + 1), KM_SLEEP);
2927*7c478bd9Sstevel@tonic-gate 			machp->m_next = pmach_head;
2928*7c478bd9Sstevel@tonic-gate 			machp->m_machname = (char *)(machp + 1);
2929*7c478bd9Sstevel@tonic-gate 			(void) strcpy(machp->m_machname, tokbuf);
2930*7c478bd9Sstevel@tonic-gate 			pmach_head = machp;
2931*7c478bd9Sstevel@tonic-gate 			break;
2932*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
2933*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
2934*7c478bd9Sstevel@tonic-gate 			break;
2935*7c478bd9Sstevel@tonic-gate 		default:
2936*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, tok_err, tokbuf);
2937*7c478bd9Sstevel@tonic-gate 			break;
2938*7c478bd9Sstevel@tonic-gate 		}
2939*7c478bd9Sstevel@tonic-gate 	}
2940*7c478bd9Sstevel@tonic-gate 	kobj_close_file(file);
2941*7c478bd9Sstevel@tonic-gate }
2942*7c478bd9Sstevel@tonic-gate 
2943*7c478bd9Sstevel@tonic-gate void *
2944*7c478bd9Sstevel@tonic-gate get_next_mach(void *handle, char *buf)
2945*7c478bd9Sstevel@tonic-gate {
2946*7c478bd9Sstevel@tonic-gate 	struct psm_mach *machp;
2947*7c478bd9Sstevel@tonic-gate 
2948*7c478bd9Sstevel@tonic-gate 	machp = (struct psm_mach *)handle;
2949*7c478bd9Sstevel@tonic-gate 	if (machp)
2950*7c478bd9Sstevel@tonic-gate 		machp = machp->m_next;
2951*7c478bd9Sstevel@tonic-gate 	else
2952*7c478bd9Sstevel@tonic-gate 		machp = pmach_head;
2953*7c478bd9Sstevel@tonic-gate 	if (machp)
2954*7c478bd9Sstevel@tonic-gate 		(void) strcpy(buf, machp->m_machname);
2955*7c478bd9Sstevel@tonic-gate 	return (machp);
2956*7c478bd9Sstevel@tonic-gate }
2957*7c478bd9Sstevel@tonic-gate 
2958*7c478bd9Sstevel@tonic-gate void
2959*7c478bd9Sstevel@tonic-gate close_mach_list(void)
2960*7c478bd9Sstevel@tonic-gate {
2961*7c478bd9Sstevel@tonic-gate 	struct psm_mach *machp;
2962*7c478bd9Sstevel@tonic-gate 
2963*7c478bd9Sstevel@tonic-gate 	while (pmach_head) {
2964*7c478bd9Sstevel@tonic-gate 		machp = pmach_head;
2965*7c478bd9Sstevel@tonic-gate 		pmach_head = machp->m_next;
2966*7c478bd9Sstevel@tonic-gate 		kmem_free(machp, sizeof (struct psm_mach) +
2967*7c478bd9Sstevel@tonic-gate 			strlen(machp->m_machname) + 1);
2968*7c478bd9Sstevel@tonic-gate 	}
2969*7c478bd9Sstevel@tonic-gate }
2970*7c478bd9Sstevel@tonic-gate #endif	/* _PSM_MODULES */
2971*7c478bd9Sstevel@tonic-gate 
2972*7c478bd9Sstevel@tonic-gate #if defined(_RTC_CONFIG)
2973*7c478bd9Sstevel@tonic-gate /*
2974*7c478bd9Sstevel@tonic-gate  * Read in the 'zone_lag' value from the rtc configuration file,
2975*7c478bd9Sstevel@tonic-gate  * and return the value to the caller.  Note that there is other information
2976*7c478bd9Sstevel@tonic-gate  * in this file (zone_info), so we ignore unknown values.  We do spit out
2977*7c478bd9Sstevel@tonic-gate  * warnings if the line doesn't begin with an identifier, or if we don't find
2978*7c478bd9Sstevel@tonic-gate  * exactly "zone_lag=value".  No one should be editing this file by hand
2979*7c478bd9Sstevel@tonic-gate  * (use the rtc command instead), but it's better to be careful.
2980*7c478bd9Sstevel@tonic-gate  */
2981*7c478bd9Sstevel@tonic-gate long
2982*7c478bd9Sstevel@tonic-gate process_rtc_config_file(void)
2983*7c478bd9Sstevel@tonic-gate {
2984*7c478bd9Sstevel@tonic-gate 	enum {
2985*7c478bd9Sstevel@tonic-gate 		R_NEW, R_NAME, R_EQUALS, R_VALUE
2986*7c478bd9Sstevel@tonic-gate 	} state;
2987*7c478bd9Sstevel@tonic-gate 	struct _buf *file;
2988*7c478bd9Sstevel@tonic-gate 	char tokbuf[MAXNAMELEN];
2989*7c478bd9Sstevel@tonic-gate 	token_t token;
2990*7c478bd9Sstevel@tonic-gate 	long zone_lag = 0;
2991*7c478bd9Sstevel@tonic-gate 	u_longlong_t tmp;
2992*7c478bd9Sstevel@tonic-gate 	int done = 0;
2993*7c478bd9Sstevel@tonic-gate 
2994*7c478bd9Sstevel@tonic-gate 	if ((file = kobj_open_file(rtc_config_file)) == (struct _buf *)-1)
2995*7c478bd9Sstevel@tonic-gate 		return (0);
2996*7c478bd9Sstevel@tonic-gate 
2997*7c478bd9Sstevel@tonic-gate 	state = R_NEW;
2998*7c478bd9Sstevel@tonic-gate 
2999*7c478bd9Sstevel@tonic-gate 	while (!done) {
3000*7c478bd9Sstevel@tonic-gate 		token = kobj_lex(file, tokbuf, sizeof (tokbuf));
3001*7c478bd9Sstevel@tonic-gate 
3002*7c478bd9Sstevel@tonic-gate 		switch (token) {
3003*7c478bd9Sstevel@tonic-gate 		case POUND:
3004*7c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
3005*7c478bd9Sstevel@tonic-gate 			break;
3006*7c478bd9Sstevel@tonic-gate 		case NAME:
3007*7c478bd9Sstevel@tonic-gate 		case STRING:
3008*7c478bd9Sstevel@tonic-gate 			if (state == R_NEW) {
3009*7c478bd9Sstevel@tonic-gate 				if (strcmp(tokbuf, "zone_lag") == 0)
3010*7c478bd9Sstevel@tonic-gate 					state = R_NAME;
3011*7c478bd9Sstevel@tonic-gate 				else
3012*7c478bd9Sstevel@tonic-gate 					kobj_find_eol(file);   /* Ignore */
3013*7c478bd9Sstevel@tonic-gate 			} else
3014*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3015*7c478bd9Sstevel@tonic-gate 			break;
3016*7c478bd9Sstevel@tonic-gate 		case EQUALS:
3017*7c478bd9Sstevel@tonic-gate 			if (state == R_NAME)
3018*7c478bd9Sstevel@tonic-gate 				state = R_EQUALS;
3019*7c478bd9Sstevel@tonic-gate 			else
3020*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3021*7c478bd9Sstevel@tonic-gate 			break;
3022*7c478bd9Sstevel@tonic-gate 		case DECVAL:
3023*7c478bd9Sstevel@tonic-gate 			if (state == R_EQUALS) {
3024*7c478bd9Sstevel@tonic-gate 				if (kobj_getvalue(tokbuf, &tmp) != 0)
3025*7c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
3026*7c478bd9Sstevel@tonic-gate 					    "Bad value %s for zone_lag",
3027*7c478bd9Sstevel@tonic-gate 					    tokbuf);
3028*7c478bd9Sstevel@tonic-gate 				else
3029*7c478bd9Sstevel@tonic-gate 					zone_lag = (long)tmp;
3030*7c478bd9Sstevel@tonic-gate 				state = R_VALUE;
3031*7c478bd9Sstevel@tonic-gate 			} else
3032*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3033*7c478bd9Sstevel@tonic-gate 			break;
3034*7c478bd9Sstevel@tonic-gate 		case EOF:
3035*7c478bd9Sstevel@tonic-gate 			done = 1;
3036*7c478bd9Sstevel@tonic-gate 			/*FALLTHROUGH*/
3037*7c478bd9Sstevel@tonic-gate 		case NEWLINE:
3038*7c478bd9Sstevel@tonic-gate 			if (state != R_NEW && state != R_VALUE)
3039*7c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
3040*7c478bd9Sstevel@tonic-gate 				    "Partial zone_lag entry ignored");
3041*7c478bd9Sstevel@tonic-gate 			kobj_newline(file);
3042*7c478bd9Sstevel@tonic-gate 			state = R_NEW;
3043*7c478bd9Sstevel@tonic-gate 			break;
3044*7c478bd9Sstevel@tonic-gate 		default:
3045*7c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, tok_err, tokbuf);
3046*7c478bd9Sstevel@tonic-gate 			break;
3047*7c478bd9Sstevel@tonic-gate 		}
3048*7c478bd9Sstevel@tonic-gate 	}
3049*7c478bd9Sstevel@tonic-gate 	kobj_close_file(file);
3050*7c478bd9Sstevel@tonic-gate 	return (zone_lag);
3051*7c478bd9Sstevel@tonic-gate }
3052*7c478bd9Sstevel@tonic-gate #endif /* _RTC_CONFIG */
3053*7c478bd9Sstevel@tonic-gate 
3054*7c478bd9Sstevel@tonic-gate 
3055*7c478bd9Sstevel@tonic-gate /*
3056*7c478bd9Sstevel@tonic-gate  * Append node spec to the end of par_list
3057*7c478bd9Sstevel@tonic-gate  */
3058*7c478bd9Sstevel@tonic-gate static void
3059*7c478bd9Sstevel@tonic-gate append(struct hwc_spec *spec, struct par_list *par)
3060*7c478bd9Sstevel@tonic-gate {
3061*7c478bd9Sstevel@tonic-gate 	struct hwc_spec *hwc, *last;
3062*7c478bd9Sstevel@tonic-gate 
3063*7c478bd9Sstevel@tonic-gate 	ASSERT(par->par_specs);
3064*7c478bd9Sstevel@tonic-gate 	for (hwc = par->par_specs; hwc; hwc = hwc->hwc_next)
3065*7c478bd9Sstevel@tonic-gate 		last = hwc;
3066*7c478bd9Sstevel@tonic-gate 	last->hwc_next = spec;
3067*7c478bd9Sstevel@tonic-gate }
3068*7c478bd9Sstevel@tonic-gate 
3069*7c478bd9Sstevel@tonic-gate /*
3070*7c478bd9Sstevel@tonic-gate  * Given a parent=/full-pathname, see if the platform
3071*7c478bd9Sstevel@tonic-gate  * can resolve the pathname to driver, otherwise, try
3072*7c478bd9Sstevel@tonic-gate  * the leaf node name.
3073*7c478bd9Sstevel@tonic-gate  */
3074*7c478bd9Sstevel@tonic-gate static major_t
3075*7c478bd9Sstevel@tonic-gate get_major(char *parent)
3076*7c478bd9Sstevel@tonic-gate {
3077*7c478bd9Sstevel@tonic-gate 	major_t major = (major_t)-1;
3078*7c478bd9Sstevel@tonic-gate 	char *tmp, *driver = NULL;
3079*7c478bd9Sstevel@tonic-gate 
3080*7c478bd9Sstevel@tonic-gate 	if (*parent == '/')
3081*7c478bd9Sstevel@tonic-gate 		major = path_to_major(parent);
3082*7c478bd9Sstevel@tonic-gate 
3083*7c478bd9Sstevel@tonic-gate 	if (major != (major_t)-1)
3084*7c478bd9Sstevel@tonic-gate 		return (major);
3085*7c478bd9Sstevel@tonic-gate 
3086*7c478bd9Sstevel@tonic-gate 	/* extract the name between '/' and '@' */
3087*7c478bd9Sstevel@tonic-gate 	if (*parent == '/')
3088*7c478bd9Sstevel@tonic-gate 		driver = strrchr(parent, '/') + 1;
3089*7c478bd9Sstevel@tonic-gate 	else
3090*7c478bd9Sstevel@tonic-gate 		driver = parent;
3091*7c478bd9Sstevel@tonic-gate 	if ((tmp = strchr(driver, '@')) != NULL)
3092*7c478bd9Sstevel@tonic-gate 		*tmp = '\0';
3093*7c478bd9Sstevel@tonic-gate 	major = ddi_name_to_major(driver);
3094*7c478bd9Sstevel@tonic-gate 	if (tmp)
3095*7c478bd9Sstevel@tonic-gate 		*tmp = '@';
3096*7c478bd9Sstevel@tonic-gate 	return (major);
3097*7c478bd9Sstevel@tonic-gate }
3098*7c478bd9Sstevel@tonic-gate 
3099*7c478bd9Sstevel@tonic-gate /*
3100*7c478bd9Sstevel@tonic-gate  * Chain together specs whose parent's module name is the same.
3101*7c478bd9Sstevel@tonic-gate  */
3102*7c478bd9Sstevel@tonic-gate static void
3103*7c478bd9Sstevel@tonic-gate add_spec(struct hwc_spec *spec, struct par_list **par)
3104*7c478bd9Sstevel@tonic-gate {
3105*7c478bd9Sstevel@tonic-gate 	major_t maj;
3106*7c478bd9Sstevel@tonic-gate 	struct par_list *pl, *par_last = NULL;
3107*7c478bd9Sstevel@tonic-gate 	char *parent = spec->hwc_parent_name;
3108*7c478bd9Sstevel@tonic-gate 
3109*7c478bd9Sstevel@tonic-gate 	ASSERT(parent || spec->hwc_class_name);
3110*7c478bd9Sstevel@tonic-gate 
3111*7c478bd9Sstevel@tonic-gate 	/*
3112*7c478bd9Sstevel@tonic-gate 	 * If given a parent=/full-pathname, see if the platform
3113*7c478bd9Sstevel@tonic-gate 	 * can resolve the pathname to driver, otherwise, try
3114*7c478bd9Sstevel@tonic-gate 	 * the leaf node name.
3115*7c478bd9Sstevel@tonic-gate 	 *
3116*7c478bd9Sstevel@tonic-gate 	 * If parent=/full-pathname doesn't resolve to a driver,
3117*7c478bd9Sstevel@tonic-gate 	 * this could be cause by DR removal of the device.
3118*7c478bd9Sstevel@tonic-gate 	 * We put it on the major=-2 list in case the device
3119*7c478bd9Sstevel@tonic-gate 	 * is brought back into the system by DR.
3120*7c478bd9Sstevel@tonic-gate 	 */
3121*7c478bd9Sstevel@tonic-gate 	if (parent) {
3122*7c478bd9Sstevel@tonic-gate 		maj = get_major(parent);
3123*7c478bd9Sstevel@tonic-gate 		if (maj == (major_t)-1) {
3124*7c478bd9Sstevel@tonic-gate 			if ((*parent == '/') &&
3125*7c478bd9Sstevel@tonic-gate 			    (strncmp(parent, "/pseudo", 7) != 0)) {
3126*7c478bd9Sstevel@tonic-gate 				maj = (major_t)-2;
3127*7c478bd9Sstevel@tonic-gate 			} else {
3128*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
3129*7c478bd9Sstevel@tonic-gate 				    "add_spec: No major number for %s",
3130*7c478bd9Sstevel@tonic-gate 				    parent);
3131*7c478bd9Sstevel@tonic-gate 				hwc_free(spec);
3132*7c478bd9Sstevel@tonic-gate 				return;
3133*7c478bd9Sstevel@tonic-gate 			}
3134*7c478bd9Sstevel@tonic-gate 		}
3135*7c478bd9Sstevel@tonic-gate 	} else
3136*7c478bd9Sstevel@tonic-gate 		maj = (major_t)-1;
3137*7c478bd9Sstevel@tonic-gate 
3138*7c478bd9Sstevel@tonic-gate 	/*
3139*7c478bd9Sstevel@tonic-gate 	 * Scan the list looking for a matching parent.
3140*7c478bd9Sstevel@tonic-gate 	 */
3141*7c478bd9Sstevel@tonic-gate 	for (pl = *par; pl; pl = pl->par_next) {
3142*7c478bd9Sstevel@tonic-gate 		if (maj == pl->par_major) {
3143*7c478bd9Sstevel@tonic-gate 			append(spec, pl);
3144*7c478bd9Sstevel@tonic-gate 			return;
3145*7c478bd9Sstevel@tonic-gate 		}
3146*7c478bd9Sstevel@tonic-gate 		par_last = pl;
3147*7c478bd9Sstevel@tonic-gate 	}
3148*7c478bd9Sstevel@tonic-gate 
3149*7c478bd9Sstevel@tonic-gate 	/*
3150*7c478bd9Sstevel@tonic-gate 	 * Didn't find a match on the list.  Make a new parent list.
3151*7c478bd9Sstevel@tonic-gate 	 */
3152*7c478bd9Sstevel@tonic-gate 	pl = kmem_zalloc(sizeof (*pl), KM_SLEEP);
3153*7c478bd9Sstevel@tonic-gate 	pl->par_major = maj;
3154*7c478bd9Sstevel@tonic-gate 	pl->par_specs = spec;
3155*7c478bd9Sstevel@tonic-gate 	if (*par == NULL) {	/* null par list */
3156*7c478bd9Sstevel@tonic-gate 		*par = pl;
3157*7c478bd9Sstevel@tonic-gate 		return;
3158*7c478bd9Sstevel@tonic-gate 	}
3159*7c478bd9Sstevel@tonic-gate 	/* put "class=" entries last (lower pri if dups) */
3160*7c478bd9Sstevel@tonic-gate 	if (maj == (major_t)-1) {
3161*7c478bd9Sstevel@tonic-gate 		par_last->par_next = pl;
3162*7c478bd9Sstevel@tonic-gate 		return;
3163*7c478bd9Sstevel@tonic-gate 	}
3164*7c478bd9Sstevel@tonic-gate 
3165*7c478bd9Sstevel@tonic-gate 	/* ensure unresolved "parent=/full-path" goes first */
3166*7c478bd9Sstevel@tonic-gate 	if ((maj != (major_t)-2) && ((*par)->par_major == (major_t)-2))
3167*7c478bd9Sstevel@tonic-gate 		par = &(*par)->par_next;
3168*7c478bd9Sstevel@tonic-gate 	pl->par_next = *par;
3169*7c478bd9Sstevel@tonic-gate 	*par = pl;
3170*7c478bd9Sstevel@tonic-gate }
3171*7c478bd9Sstevel@tonic-gate 
3172*7c478bd9Sstevel@tonic-gate /*
3173*7c478bd9Sstevel@tonic-gate  * Add property spec to property list in original order
3174*7c478bd9Sstevel@tonic-gate  */
3175*7c478bd9Sstevel@tonic-gate static void
3176*7c478bd9Sstevel@tonic-gate add_props(struct hwc_spec *spec, ddi_prop_t **props)
3177*7c478bd9Sstevel@tonic-gate {
3178*7c478bd9Sstevel@tonic-gate 	ASSERT(spec->hwc_devi_name == NULL);
3179*7c478bd9Sstevel@tonic-gate 
3180*7c478bd9Sstevel@tonic-gate 	if (spec->hwc_devi_sys_prop_ptr) {
3181*7c478bd9Sstevel@tonic-gate 		while (*props)
3182*7c478bd9Sstevel@tonic-gate 			props = &(*props)->prop_next;
3183*7c478bd9Sstevel@tonic-gate 		*props = spec->hwc_devi_sys_prop_ptr;
3184*7c478bd9Sstevel@tonic-gate 
3185*7c478bd9Sstevel@tonic-gate 		/* remove these properties from the spec */
3186*7c478bd9Sstevel@tonic-gate 		spec->hwc_devi_sys_prop_ptr = NULL;
3187*7c478bd9Sstevel@tonic-gate 	}
3188*7c478bd9Sstevel@tonic-gate 	hwc_free(spec);
3189*7c478bd9Sstevel@tonic-gate }
3190