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