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