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