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