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