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