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