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